【题目链接】 http://acm.hdu.edu.cn/showproblem.php?pid=6017
【题目大意】
给出一个只包含2和3的串,你可以花费两个智力值交换相邻的两个字符
问在智力值不降到负数的情况下,可以产生多少个233子串
【题解】
dp[i][j][k][t]表示在放入前i+j串用了i个2和j个3代价为k,结尾状态为t的最优答案
t状态分别为2,23,233三种状态,我们在这个题目中,2和3内部都是不会发生交换的
所以代价只为2和3交换的次数,等价于最后每个2的末位置和初位置的差值,
枚举2和3的数量,代价和状态,dp即可
【代码】
#include <cstdio> #include <cstring> #include <algorithm> using namespace std; typedef long long LL; #define REP(i,a,b) for(int i=a;i<=b;i++) const int N=110,inf=0x3f3f3f3f; int T,n,m,x,y,dp[N][N][N][3],a[N]; char s[N]; void up(int &a,int b){if(a<b)a=b;} int main(){ scanf("%d",&T); while(T--){ scanf("%d%d%s",&n,&m,s+1); m/=2; int ca=0,cb=0; REP(i,1,n)if(s[i]=='2')a[++ca]=i;else cb++; REP(i,0,ca)REP(j,0,cb)REP(k,0,m)REP(t,0,2)dp[i][j][k][t]=-inf; dp[0][0][0][0]=0; REP(i,0,ca)REP(j,0,cb)REP(k,0,m)REP(t,0,2)if(dp[i][j][k][t]>=0){ if(i<ca){ int x=k+abs(i+j+1-a[i+1]); if(x<=m)up(dp[i+1][j][x][1],dp[i][j][k][t]); } if(j<cb){ int x=t,y=dp[i][j][k][t]; if(x)if(x<2)x++;else x=0,y++; up(dp[i][j+1][k][x],y); } }int ans=0; REP(k,0,m)REP(t,0,2)up(ans,dp[ca][cb][k][t]); printf("%d ",ans); }return 0; }