AT_agc040_e [AGC040E] Prefix Suffix Addition 题解
比较巧的题。
先考虑只有 \(1\) 操作时怎么做,显然答案为满足 \(1\le i<n\land A_i>A_{i+1}\) 的 \(i\) 的个数,即每次选一段尽量长的不降段进行操作。
接下来加上 \(2\) 操作,考虑对每个 \(i\) 将 \(A_i\) 分为 \(x_i\) 和 \(A_i-x_i\),\(x_i\) 用 \(1\) 操作,\(A_i-x_i\) 用 \(2\) 操作,答案即为 \(\sum_{i=2}^n [x_i<x_{i-1}]+[A_i-x_i>A_{i-1}-x_{i-1}]\),即 \(\sum_{i=2}^n [x_i<x_{i-1}]+[x_i<x_{i-1}+A_i-A_{i-1}]\)。容易得到一个比较暴力的 dp:记 \(f_{i,j}\) 表示确定 \(x_1,x_2,\dots,x_i\),\(x_i\) 为 \(j\) 的最少代价,有:
\[f_{i,j}=\min_{k=0}^{A_{i-1}}\{f_{i-1,k}+[j<k]+[j<k+A_i-A_{i-1}]\}
\]
发现 \([j<k]+[j<k+A_i-A_{i-1}]\) 总共有三种值,对每个 \(i\) 把 \(f_{i,j}\) 分成了三段,记录前两段的右端点直接转移即可,时间复杂度 \(\mathcal O(n)\)。
参考代码:
#include<bits/stdc++.h>
#define ll long long
#define mxn 200003
#define rep(i,a,b) for(int i=(a);i<=(b);++i)
#define rept(i,a,b) for(int i=(a);i<(b);++i)
#define drep(i,a,b) for(int i=(a);i>=(b);--i)
using namespace std;
int n,ans,a[mxn],f[mxn][2];
signed main(){
scanf("%d",&n);
rep(i,1,n)scanf("%d",&a[i]);
rep(i,1,n){
if(a[i]>=a[i-1]){
f[i][0]=f[i-1][0];
f[i][1]=max(f[i-1][1],f[i-1][0]+a[i]-a[i-1]);
}else{
f[i][0]=f[i-1][0]+a[i]-a[i-1];
f[i][1]=max(f[i-1][0],f[i-1][1]+a[i]-a[i-1]);
if(f[i][0]<0){
ans++;
f[i][0]=f[i][1],f[i][1]=a[i];
}
}
f[i][0]=min(f[i][0],a[i]);
f[i][1]=min(f[i][1],a[i]);
}
cout<<ans+(f[n][0]<a[n]);
return 0;
}

浙公网安备 33010602011771号