JZOJ4737 金色丝线将瞬间一分为二

Description

Input

Output

Sample Input

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

Sample Output

4

Data Constraint

Hint


Solution

  首先,每个点的横纵坐标相互独立,所以可以分开来做。 先考虑一个 n log^2 n 的做法: 二分答案 ans,将前 1~ans 个数排序,然后对于第 i 个数 x,它的贡献是 i*x-sum[i],sum[i] 表示排序后前 i 个数的和。 注意到这个做法的时间浪费在 log n 次排序上,而排序的时间复杂度是 n log n 的。 我们可以一开始先将 n 个点进行 n log n 的排序,然后再 O(N)算出每个数的排名,这样在二分 答案中的排序就可以做到 O(N)。

  

 1 #include<cstdio>
 2 #include<algorithm>
 3 using namespace std;
 4 int n;
 5 long long d,s[1000000],ss[1000000];
 6 struct arr
 7 {
 8     int z,w;
 9 }x[1000000],y[1000000];
10 bool cmp(arr x,arr y)
11 {
12     return x.z<y.z;
13 }
14 bool pd(int xx)
15 {
16     int t=0;
17     for (int i=1;i<=n;i++)
18         if (x[i].w<=xx)
19             s[++t]=x[i].z;
20     long long sum=0;
21     for (int i=1;i<=xx;i++)
22     {
23         sum+=s[i]*(i-1)-ss[i-1];
24         ss[i]=ss[i-1]+s[i];
25     }
26     t=0;
27     for (int i=1;i<=n;i++)
28         if (y[i].w<=xx)
29             s[++t]=y[i].z;
30     for (int i=1;i<=xx;i++)
31     {
32         sum+=s[i]*(i-1)-ss[i-1];
33         ss[i]=ss[i-1]+s[i];
34     }
35     if (sum<=d) return true;
36     else return false;
37 }
38 int main()
39 {
40     scanf("%d%lld",&n,&d);
41     for (int i=1;i<=n;i++)
42     {
43         scanf("%lld%lld",&x[i].z,&y[i].z);
44         x[i].w=y[i].w=i;
45     }
46     sort(x+1,x+n+1,cmp);
47     sort(y+1,y+n+1,cmp);
48     int l=1,r=n;
49     while (l<r)
50     {
51         int mid=(l+r)/2;
52         if (pd(mid))
53             l=mid+1;
54         else r=mid;
55     }
56     if (l==n&&pd(l))
57         printf("-1");
58     else printf("%d",l);
59 }
View Code

 

posted @ 2018-08-25 09:08 kasiruto 阅读(...) 评论(...) 编辑 收藏