1945. 奶牛棒球 题型:双指针

101 阅读1分钟

1945. 奶牛棒球 - AcWing题库

写个暴力法O(n^3)竟然过了,数据有点水。暴力法虽然不好,但是可以帮助我们理解:

#include<bits/stdc++.h>
using namespace std;
const int N=1e8+10;
int a[N];
int n,ans;
int main()
{
    cin>>n;
    for(int i=0;i<n;i++)
    {
        cin>>a[i];
    }
    sort(a,a+n);
    for(int x=0;x<n;x++)
    {
        for(int y=x+1;y<n;y++)
        {
            for(int z=y+1;z<n;z++)
            {
                int xy=a[y]-a[x];
                int yz=a[z]-a[y];
                
                if(yz>=xy&&yz<=2*xy)
                {
                    ans++;
                }
            }
        }
    }
    
    cout<<ans;
    return 0;
}

image.png




题目说了xy<=yz<=2xyxy<=yz<=2xy: image.png

ok,现在我们从点的角度来看: image.png yx<=zy<=2(yx)y-x<=z-y<=2(y-x)

2yx<=z<=3y2x2y-x<=z<=3y-2x

ok,这道题的数据范围是10001000,我们可以枚举x,y这两个点,也就是O(n2)O(n^2),也就是1e61e6,第三个点z我们可以在上面求出来的z的范围里去,[2yx,3y2x][2y-x,3y-2x]里有多少个点,就说明有多少个合法的z。

第三个点的复杂度我们要控制在 nlongnnlongn,这样的话整体的复杂度是 O(n2nlong)O(n^2 nlong)

image.png

那么现在我们的问题就是求怎么找到[2yx,3y2x][2y-x,3y-2x],观察下图我们发现我们可以将问题转变为求:

大于等于2y-x的最大的点

小于等于3y-2x的最大的点

image.png

#include<bits/stdc++.h>
using namespace std;
const int N=1010;
int ans,n;
int a[N];
int main()
{
    cin >>n;
    for(int i=0;i<n;i++)cin>>a[i];
    sort(a,a+n);
    for(int i=0;i+2<n;i++) //给j,z留空
    {
        for(int j=i+1,l=i+1,r=i+1;j+1<n;j++) //j+1<n是为了给z留空
        {
            while(l<n&&a[l]-a[j]<a[j]-a[i])l++;   //xy<=yz
            while(r<n&&a[r]-a[j]<=2*(a[j]-a[i]))r++;      //yz<=2(xy)
            ans+=r-l;  //[L,R]之间的就是z的所有合法可取点,全部加上
        }
    }
    
    cout<<ans<<endl;
    return 0;
}