BZOJ2792: [Poi2012]Well

来源:互联网 发布:nginx conf 配置 编辑:程序博客网 时间:2024/05/26 02:51

先二分z
然后将序列调整成相邻数字的差都不超过z
计算对于每个位置i将它调成0,维护序列需要的操作次数,比如计算左侧的贡献,用j表示最左一个点不满足abs(a[i]-a[j])<=(i-j)*z,随i的增加j单调递增,且因为之前已经将序列调整过使得相邻数字差不超过z,所以可以O(1)算出j~i调整的操作次数,对于右侧点类似

code:

#include<set>#include<map>#include<deque>#include<queue>#include<stack>#include<cmath>#include<ctime>#include<bitset>#include<string>#include<vector>#include<cstdio>#include<cstdlib>#include<cstring>#include<climits>#include<complex>#include<iostream>#include<algorithm>#define ll long long#define lowbit(x) x&(-x)using namespace std;void read(ll &x){    char c;    while(!((c=getchar())>='0'&&c<='9'));    x=c-'0';    while((c=getchar())>='0'&&c<='9') x=(x<<3)+(x<<1)+c-'0';}const int maxn = 1100000;ll n,m,a[maxn];ll b[maxn];ll l,r;ll s[maxn];ll lx[maxn],rx[maxn];ll judge(ll x){    ll sum=0;    for(ll i=1;i<=n;i++) s[i]=0,b[i]=a[i];    for(ll i=2;i<=n;i++)    {        if(b[i]>b[i-1]+x) sum+=b[i]-b[i-1]-x,b[i]=b[i-1]+x;    }    for(ll i=n-1;i>=1;i--)    {        if(b[i]>b[i+1]+x) sum+=b[i]-b[i+1]-x,b[i]=b[i+1]+x;    }    if(sum>m) return 0;    for(ll i=1;i<=n;i++) s[i]=s[i-1]+b[i];    ll left,right;    left=1;    for(ll i=1;i<=n;i++)    {        while(left<i&&b[left]<=(i-left)*x) left++;        lx[i]=left==i?0:s[i-1]-s[left-1]-x*(i-left+1ll)*(i-left)/2ll;    }    right=n;    for(ll i=n;i>=1;i--)    {        while(right>i&&b[right]<=(right-i)*x) right--;        rx[i]=right==i?0:s[right]-s[i]-x*(right-i+1ll)*(right-i)/2ll;    }    for(ll i=1;i<=n;i++)        if(sum+lx[i]+rx[i]+b[i]<=m) return i;    return 0;}ll solve(ll &ans){    ll temp;    while(l<=r)    {        ll mid=(l+r)>>1;        if(temp=judge(mid)) r=mid-1,ans=temp;        else l=mid+1;    }    return r+1;}int main(){    read(n); read(m);    l=r=0;    for(ll i=1;i<=n;i++)     {        read(a[i]);        if(r<a[i]) r=a[i];    }    ll Z,K;    Z=solve(K);    printf("%lld %lld\n",K,Z);    return 0;}
0 0
原创粉丝点击