[BZOJ2792][Poi2012]Well

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[BZOJ2792][Poi2012]Well相关的知识,希望对你有一定的参考价值。

2792: [Poi2012]Well

Time Limit: 40 Sec  Memory Limit: 64 MB
Submit: 137  Solved: 61
[Submit][Status][Discuss]

Description

 给出n个正整数X1,X2,...Xn,可以进行不超过m次操作,每次操作选择一个非零的Xi,并将它减一。

最终要求存在某个k满足Xk=0,并且z=max{|Xi - Xi+1|}最小。
输出最小的z和此时最小的k。
 
 
 

Input

 

第一行两个正整数n, m (1<=n<=1,000,000, 1<=m<=10^18)。第二行n个正整数X1,X2,...Xn (Xi<=10^9)。
 
 
 

Output

 

输出k和z。数据保证方案一定存在。
 
 
 

Sample Input

16 15
8 7 6 5 5 5 5 5 6 6 7 8 9 7 5 5

Sample Output

1 2

HINT

 

 将X序列变为


0 2 4 5 5 5 5 5 6 6 7 8 9 7 5 5

 

此时k=1,z=2,共操作了8+5+2=15次。

 

 

Source

[Submit][Status][Discuss]


要求最小化最大值,肯定想到二分。

二分判定的难点在于如何求最小的能等于0的数。

假如要把i位置变成0,则一定会修改一个区间[L,R]

所以必须满足a[L]>(i-L)*mid,且a[R]>(R-i)*mid

这两个显然都是单调的,然后[L,R]这个区间要想修改最小的话,最后一定变成前后两个等差数列,其中公差=mid,第i项=0,直接统计答案即可。

技术分享
 1 #include<cstdio>
 2 #include<algorithm>
 3 #define N 1000010
 4 #define mid (l+r>>1)
 5 #define ll long long
 6 using namespace std;
 7 int n,a[N],b[N];
 8 ll m,f[N],sum[N];
 9 inline int check(int x)
10 {
11     ll ans=0;
12     for(int i=1;i<=n;i++)b[i]=a[i];
13     for(int i=2;i<=n;i++)
14     if(b[i]-b[i-1]>x)
15     ans+=b[i]-b[i-1]-x,b[i]=b[i-1]+x;
16     for(int i=n-1;i;i--)
17     if(b[i]-b[i+1]>x)
18     ans+=b[i]-b[i+1]-x,b[i]=b[i+1]+x;
19     for(int i=1;i<=n;i++)
20     sum[i]=sum[i-1]+b[i];
21     if(ans>m)return 0;
22     for(int i=1,j=1;i<=n;i++)
23     {
24         while(j<i&&b[j]<=(ll)(i-j)*x)j++;
25         f[i]=sum[i-1]-sum[j-1]-(ll)(i-j)*(i-j+1)/2*x;
26     }
27     for(int i=n,j=n;i;i--)
28     {
29         while(j>i&&b[j]<=(ll)(j-i)*x)j--;
30         f[i]+=sum[j]-sum[i]-(ll)(j-i)*(j-i+1)/2*x;
31     }
32     for(int i=1;i<=n;i++)
33     if(b[i]+f[i]+ans<=m)return i;
34     return 0;
35 }
36 int main()
37 {
38     int l=0,r=0,ans=0;
39     scanf("%d%lld",&n,&m);
40     for(int i=1;i<=n;i++)
41     scanf("%d",&a[i]),r=max(r,a[i]);
42     while(l<=r)
43     {
44         if(check(mid))ans=mid,r=mid-1;
45         else l=mid+1;
46     }
47     printf("%d %d",check(ans),ans);
48 }
View Code

 

以上是关于[BZOJ2792][Poi2012]Well的主要内容,如果未能解决你的问题,请参考以下文章

[BZOJ2797][Poi2012]Squarks

[BZOJ2799][Poi2012]Salaries

[BZOJ2791][Poi2012]Rendezvous

[BZOJ2793][Poi2012]Vouchers

[BZOJ2790][Poi2012]Distance

bzoj2796 [Poi2012]Fibonacci Representation