题目大意:一个由2和3组成的长度为n的串,有m/2次机会操作(将相邻两个数交换),问最多可以得到多少个233?
题解&代码:
/*
dp[i][j][k]表示第i个2放在第j位,用了k次操作的233最多个数。
*/
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define max(a,b) ((a)>(b)?(a):(b))
#define MAXN 105
int dp[MAXN][MAXN][MAXN];
int pos[MAXN];
int main()
{
int T,n,m,i,j,k,l,x,ans,ct,mov;
scanf("%d",&T);
while(T--)
{
scanf("%d%d",&n,&m);
m/=2;
ct=0;
memset(dp,-1,sizeof dp);
for(i=1;i<=n;i++)
{
scanf("%1d",&x);
if(x==2)
pos[++ct]=i;
}
dp[0][0][0]=0;
for(i=1;i<=ct;i++)//i从1枚举到2的个数
for(j=i,mov=abs(pos[i]-j);j<=n-ct+i;j++,mov=abs(pos[i]-j))//j至少放在第i位(把i个2挤在前面),最多放在n-ct+i位(把i个2挤在最后面),mov第i个2需要移动步数。
for(k=mov;k<=m;k++)//操作次数
{
for(l=i-1;l<=j-1;l++)
if(~dp[i-1][l][k-mov])//上一状态可行
dp[i][j][k]=max(dp[i][j][k],dp[i-1][l][k-mov]+(j-l>2&&l!=0));//加上是否新产生233
}
ans=0;
if(ct!=0)
for(j=ct,mov=abs(pos[ct]-j);j<=n;j++,mov=abs(pos[ct]-j))
for(k=mov;k<=m;k++)//枚举最后一个2的状态
ans=max(ans,dp[ct][j][k]+(j<=n-2));//加上最后一个2是否产生233
printf("%d\n",ans);
}
return 0;
}