• [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
    就让我永远不在这里写什么有意义的话--月下孤狼
  • 相关阅读:
    关于轨道交通的一些知识点和关键词
    关于芯片的一些关键词
    关于ADC采集
    Linux记录
    在VMware运行Linux下,密码错误的原因
    气体传感器
    AD采集问题
    Maven [ERROR] 不再支持源选项 5,请使用 7 或更高版本的解决办法
    Maven 专题(九):后记
    Maven 专题(六):Maven核心概念详解(二)
  • 原文地址:https://www.cnblogs.com/xuruifan/p/5189416.html
Copyright © 2020-2023  润新知