Brief Introduction:
给定一个仅由abc组成的字符串,每个字符可以向左右延展,求最终新的平衡字符串的个数。
Algorithm:
关键点在于变换前后字符串中字符的相对位置不会发生改变
也就是说,将前后字符串unique后,B是A的子序列
问题转化为求A得子序列数
这样直接使用dp[cur][i][j][k] 配合 next[i][char] 转移即可
不过在实际实现中可以不用unique,直接在原字符串上转移也是同样的效果
Code:
#include <bits/stdc++.h> using namespace std; const int m=51123987; int n,nxt[155][3],dp[155][55][55][55],res=0; char dat[155]; bool check(int a,int b,int c) { if(abs(a-b)>1) return false; if(abs(a-c)>1) return false; if(abs(b-c)>1) return false; return true; } int main() { cin >> n; for(int i=1;i<=n;i++) cin >> dat[i]; for(int i=n;i;i--) { nxt[i][0]=nxt[i+1][0],nxt[i][1]=nxt[i+1][1]; nxt[i][2]=nxt[i+1][2],nxt[i][dat[i]-'a']=i; } int most=n/3+2;dp[1][0][0][0]=1; for(int cur=1;cur<=n;cur++) for(int i=0;i<=most;i++) for(int j=0;j<=most;j++) for(int k=0;k<=most;k++) if(dp[cur][i][j][k]) { if(i+j+k==n && check(i,j,k)) //向答案贡献的条件 res=(res+dp[cur][i][j][k])%m; int &a=dp[nxt[cur][0]][i+1][j][k]; int &b=dp[nxt[cur][1]][i][j+1][k]; int &c=dp[nxt[cur][2]][i][j][k+1]; a=(a+dp[cur][i][j][k])%m; b=(b+dp[cur][i][j][k])%m; c=(c+dp[cur][i][j][k])%m; } cout << res; return 0; }
Review:
抓住不变量解题,发现相对位置不变使用类似 完全背包 的DP解题