显然,这是一道动归题。
我们发现,每次交换时只可能交换不同的字母(交换同类字母显然是没有意义的)。那么每次交换等同于将 111 个 "j""j""j" 变为 "z""z""z",一个 zzz 变为 "j""j""j"。
定义状态 dp[i][a][b]dp[i][a][b]dp[i][a][b],即考虑到第 iii 个字符,将 aaa 个 jjj 进行变换,bbb 个 "z""z""z" 进行变换的最大价值。
对于相邻的字母,只有4种可能,也只有4种转移方程,分别为:
- jjjjjj: dp[i][a][b]=dp[i−2][a−1][b]+1dp[i][a][b]=dp[i-2][a-1][b]+1dp[i][a][b]=dp[i−2][a−1][b]+1
- jzjzjz:dp[i][a][b]=dp[i−2][a][b]+1dp[i][a][b]=dp[i-2][a][b]+1dp[i][a][b]=dp[i−2][a][b]+1
- zjzjzj:dp[i][a][b]=dp[i−2][a−1][b−1]+1dp[i][a][b]=dp[i-2][a-1][b-1]+1dp[i][a][b]=dp[i−2][a−1][b−1]+1
- zzzzzz:dp[i][a][b]=dp[i−2][a][b−1]+1dp[i][a][b]=dp[i-2][a][b-1]+1dp[i][a][b]=dp[i−2][a][b−1]+1
Code:
#include<cstdio> #include<algorithm> #include<cstring> using namespace std; const int maxn=600; int d[maxn][120][120]; char A[maxn]; int main() { int N,K,ans=0; scanf("%d%d",&N,&K); scanf("%s",A+1); memset(d,-0x3f,sizeof(d)); d[0][0][0]=0; d[1][0][0]=0; if(A[1]=='z')d[1][0][1]=0; else d[1][1][0]=0; for(int n=2;n<=N;++n) for(int j=0;j<=K;++j) for(int z=0;z<=K;++z) { d[n][j][z]=d[n-1][j][z]; if(A[n-1]=='j'&&A[n]=='j'&&j>=1)d[n][j][z]=max(d[n][j][z],d[n-2][j-1][z]+1); if(A[n-1]=='j'&&A[n]=='z')d[n][j][z]=max(d[n][j][z],d[n-2][j][z]+1); if(A[n-1]=='z'&&A[n]=='z'&&z>=1)d[n][j][z]=max(d[n][j][z],d[n-2][j][z-1]+1); if(A[n-1]=='z'&&A[n]=='j'&&z>=1&&j>=1)d[n][j][z]=max(d[n][j][z],d[n-2][j-1][z-1]+1); if(j==z)ans=max(ans,d[n][j][z]); } printf("%d",ans); return 0; }