2792: [Poi2012]Well
Time Limit:
给出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
代码如下:
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define N 1000010
#define dnt long long
#define inf 1e9
dnt n,m;
dnt a[N],b[N];
dnt L[N],R[N],pre[N],ans;
bool check(long long x)
{
for(dnt i=1;i<=n;++i)
b[i]=a[i];
long long tot=0;
for(dnt i=2;i<=n;++i)
if(b[i]-b[i-1]>x)
{
tot+=b[i]-b[i-1]-x;
b[i]=b[i-1]+x;
}
for(dnt i=n-1;i>=1;--i)
if(b[i]-b[i+1]>x)
{
tot+=b[i]-b[i+1]-x;
b[i]=b[i+1]+x;
}
dnt j=1;
for(dnt i=1;i<=n;++i)
{
while(b[j]<=(i-j)*x&&i>j) ++j;
L[i]=j;
}
j=n;
for(dnt i=n;i>=1;--i)
{
while(b[j]<=(j-i)*x&&i<j) --j;
R[i]=j;
}
for(dnt i=1;i<=n;++i) pre[i]=pre[i-1]+b[i];
for(dnt i=1;i<=n;++i)
if(tot+pre[R[i]]-pre[L[i]-1]-x*((R[i]-i)*(R[i]-i+1)+(i-L[i])*(i-L[i]+1))/2<=m)
{
ans=i;
return true;
}
return false;
}
int main()
{
scanf("%lld%lld",&n,&m);
for(dnt i=1;i<=n;++i) scanf("%lld",&a[i]);
dnt l=0,r=inf,mid;
while(l<r)
{
mid=(l+r)>>1;
if(!check(mid)) l=mid+1;
else r=mid;
}
printf("%lld %lld",ans,l);
return 0;
}