BZOJ 2792 [POI 2012] 二分答案 解题报告

来源:互联网 发布:查微信聊天记录软件 编辑:程序博客网 时间:2024/05/16 10:52

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 1e9dnt 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;}
阅读全文
0 0