CF1425E Excitation of Atoms
http://codeforces.com/problemset/problem/1425/E
设 \(sum_i\) 为前缀和,\(gain_i\) 为 \(\max sum_n-sum_{j-1}-D_j,j\ge i\),\(gain2_i\) 为 \(\max sum_n-sum_{j-1}-D_j,j\le i\)
k=0
显然 \(ans=max(gain_1,0)\)
k>1
构造,对于一个 \(i\),将 \(E_i\) 改为 \(1\),将 \(E_{i-1}\) 改为 \(i+1\)
这样可以激发所有原子,只要将 \(i\) 选为 \(D_i\) 最小的即可
k=1
分两种情况
将 \(E_i\) 向前改,此时肯定改为 \(1\),同样代价把前面都选上才会最优
这样如果要激发 \([1,i]\),只需花费 \(min=\min D_j,j\le i\) 的代价
如果要激发 \([i+1,n]\) 中的某个子段,用 \(gain\) 计算
答案为 \(sum_i-min+\max(gain_{i+1},0)\),枚举所有 \(i\) 取最大值
将 \(E_{i-1}\) 向后改,此时肯定改为 \(i+1\),否则少取中间跳过的一段也不会最优
如果激发点 \(j\ge i\),答案为 \(gain_i\),和 \(k=0\) 的类似
如果激发点 \(j<i\),那么会激发 \([j,n]\) 所有点除去 \(i\),再考虑 \(i\) 要不要单独激发一下,答案是 \(gain2_{i-1}-\min(D_i,A_i)\)
单独再激发一下 \(i\) 的情况已经包含了两个激发点同时在 \(i\) 的前后,不用单独考虑这种两个激发点的情况了
仍然枚举 \(i\) 取最大值
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<map>
#define reg register
inline int read(){
register int x=0;register int y=0;
register char c=getchar();
while(c<'0'||c>'9'){if(c=='-')y=1;c=getchar();}
while(c>='0'&&c<='9') x=x*10+c-48,c=getchar();
return y?-x:x;
}
#define N 100006
int n;
long long sum[N],a[N],gain[N],gain_[N];
long long d[N];
int main(){
n=read();int k=read();
for(reg int i=1;i<=n;i++) sum[i]=sum[i-1]+(a[i]=read());
for(reg int i=1;i<=n;i++) d[i]=read();
for(reg int i=1;i<=n;i++) gain[i]=sum[n]-sum[i-1]-d[i],gain_[i]=std::max(gain_[i-1],gain[i]);
for(reg int i=n-1;i;i--) gain[i]=std::max(gain[i],gain[i+1]);
if(!k) return printf("%lld",std::max(gain[1],0ll)),0;
if(k>1){
long long ans=sum[n]-d[1];
for(reg int i=2;i<n;i++) ans=std::max(ans,sum[n]-d[i]);
ans=std::max(ans,a[n]-d[n]);
printf("%lld",std::max(ans,0ll));
return 0;
}
long long ans=0;
long long min=std::min(d[1],d[2]);
for(reg int i=2;i<n;i++){
ans=std::max(ans,sum[i]-min+std::max(0ll,gain[i+1]));//向前改
min=std::min(min,d[i+1]);
}
for(reg int i=2;i<n;i++){
ans=std::max(ans,std::max(gain[i],gain_[i-1]-std::min(a[i],d[i])));//向后改
// ans=std::max(ans,gain[])
}
for(reg int i=2;i<=n;i++) ans=std::max(ans,sum[n]-sum[i-1]-d[i]);
printf("%lld",ans);
return 0;
}