【JZOJ A组】金色丝线将瞬间一分为二

Description

【JZOJ A组】金色丝线将瞬间一分为二_第1张图片

Input

这里写图片描述

Output

这里写图片描述

Sample Input

5 10
1 1
2 2
3 3
4 4
5 5

Sample Output

4

Data Constraint

这里写图片描述

Hint

这里写图片描述

思路

首先,我们考虑n log^2 n的做法。
不难发现,x和y可以分开单独处理
二分答案ans,把1到ans的元素排序,然后查询每一个数对答案的贡献。

现在我们要减少一个log

发现二分时并不需要每次排序。
我们可以事先给整个序列排序,则可以得到所有数字的排名。
二分时直接O(n)桶排即可。

代码

%:pragma GCC optimize(3)
#include
#include
#include
#include
using namespace std;
const int maxn=6e5+77;
long long x[maxn],y[maxn],d,ans=0,a[maxn],s[maxn],b[maxn];
int n,d1[maxn],d2[maxn];
bool cmpx(int a,int b) { return x[a]bool cmpy(int a,int b) { return y[a]int main()
{
    scanf("%d%lld",&n,&d);
    for(int i=1; i<=n; i++)
    {
        scanf("%lld%lld",&x[i],&y[i]);
        d1[i]=d2[i]=i;
    }
    sort(d1+1,d1+n+1,cmpx); sort(d2+1,d2+n+1,cmpy);
//  for(int i=1; i<=n; i++) printf("x[d1[%d]]=%d\n",i,x[d1[i]]);
    int l=1,r=n+1;
    while(l<=r)
    {
        int mid=(l+r)>>1; ans=0;
        memset(a,-1,sizeof(a));
        for(int i=1; i<=n; i++) if(d1[i]<=mid) a[i]=x[d1[i]];
        int t=0;
        for(int i=1; i<=n; i++) if(a[i]>=0) 
            s[++t]=s[t-1]+a[i],b[t]=a[i];
        for(int i=1; i<=mid; i++) ans+=i*b[i]-s[i];
        memset(a,-1,sizeof(a));
        for(int i=1; i<=n; i++) if(d2[i]<=mid) a[i]=y[d2[i]];
        t=0;
        for(int i=1; i<=n; i++) if(a[i]>=0) s[++t]=s[t-1]+a[i],b[t]=a[i];
        for(int i=1; i<=mid; i++) ans+=i*b[i]-s[i];
        if(ans>=d) r=mid-1;else l=mid+1;
    }
    printf("%d",r==n+1?-1:l);
}

你可能感兴趣的:(题解,二分)