Codeforces Round #670 (Div. 2)D. Three Sequences(非降非升序列组成已知序列,求最小化最大值)
题:http://codeforces.com/contest/1406/problem/D
题意:给定a数组,要求b序列(非降)和c序列(非升)组成a序列(bi+ci=ai),要求输出最小化的最大值max(b1,ci),支持区间加操作
分析:先考虑只求原序列的答案,假设bn=b1+sum(sum>=0,因为是上升序列),由定义:c1=a1-b1;
而经过观察,a序列中差分为正的就由b来处理,差分为负的就由c来处理,所以sum=Σ(差分为正)。
那么答案就是max(bn,c1)化简得max(b1+sum,a1-b1);
只有两种情况:
- b1+sum>=a1-b1,那么b1要满足b1>=(a1-sum)/2,就选前者;
- b1+sum<=a1-b1,那么b1要满足b1<=(a1-sum)/2,就选后者;
然后,因为我们要最小化这个值,那么选择前者时,b1不能大太大,选择后者时b1不能小太小,所以综合b1=(a1-sum)/2。
接着就是区间加,影响的就只有l ,r+1位置的差分值,简单维护一下更新答案。
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int M=2e5+5; ll a[M],dis[M]; int main(){ int n; scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%lld",&a[i]); ll sum=0; for(int i=2;i<=n;i++) sum+=max(0ll,a[i]-a[i-1]),dis[i]=a[i]-a[i-1]; ll b1=(a[1]-sum)/2; printf("%lld\n",max(b1+sum,a[1]-sum)); int m; scanf("%d",&m); for(int l,r,x,i=1;i<=m;i++){ scanf("%d %d %d",&l,&r,&x); /// if(l==1) a[1]+=1ll*x; else{ ll las=dis[l];///上次差分值 sum-=max(0ll,las); sum+=max(0ll,las+x); dis[l]+=x; } /// if(r!=n){ ll las=dis[r+1]; sum-=max(0ll,las); sum+=max(0ll,las-x); dis[r+1]-=x; } b1=(a[1]-sum)/2; printf("%lld\n",max(b1+sum,a[1]-sum)); } return 0; }