P2824 [HEOI2016/TJOI2016] 排序
P1136 迎接仪式
动态规划好题
状态设计:
我们认为z是1,j是0,产生贡献的是01对
我们用状态 \(f[i][j][k][0/1]\) 表示考虑到第 \(i\) 位,进行了 \(j\) 次将1变成0的操作和 \(k\) 次将0变成1的操作,操作过后第 \(i\) 位为 \(0/1\) 时的答案
状态转移:
然后我们就有方程:
\(a_i=1:\)
\( f[i][j][k][1]=max(f[i-1][j][k][0]+1,f[i-1][j][k][1]); \)
$ f[i][j][k][0]=max(f[i-1][j-1][k][0],f[i-1][j-1][k][1]);
$
\(a_i=0:\)
\( f[i][j][k][0]=max(f[i-1][j][k][0],f[i-1][j][k][1]); \)
\( f[i][j][k][1]=max(f[i-1][j][k-1][0]+1,f[i-1][j][k-1][1]); \)
当且仅当 \(j=k\) 时答案合法
然后这题就做完了
Code:
#include<bits/stdc++.h> const int N=505; const int K=105; const int inf=1e9; using namespace std; int f[N][K][K][2],a[N]; int n,m,ans; char c[N]; void init() { for(int i=0;i<N;i++)for(int j=0;j<K;j++)for(int k=0;k<K;k++)f[i][j][k][0]=f[i][j][k][1]=-inf; } void work() { init(); cin>>n>>m; scanf("%s",c+1); f[0][0][0][1]=0; for(int i=1;i<=n;i++) { bool now = c[i]=='z'; for(int j=0;j<=m;j++) { for(int k=0;k<=m;k++) { //01 //1: if(now) { f[i][j][k][1]=max(f[i-1][j][k][0]+1,f[i-1][j][k][1]); if(j)f[i][j][k][0]=max(f[i-1][j-1][k][0],f[i-1][j-1][k][1]); } //0: else { f[i][j][k][0]=max(f[i-1][j][k][0],f[i-1][j][k][1]); if(k)f[i][j][k][1]=max(f[i-1][j][k-1][0]+1,f[i-1][j][k-1][1]); } } } } for(int i=1;i<=m;i++)ans=max({ans,f[n][i][i][0],f[n][i][i][1]}); printf("%d",ans); } int main() { //freopen("welcome.in","r",stdin); //freopen("welcome.out","w",stdout); work(); }