这题在网上看到一个非常容易理解的思路,和大家分享一下。
记dp[i][j]为前i个字符删除j个字符后得到不同字符串的数量,可以得到以下两个转移方程
dp[i][j+1]=dp[i][j+1]+dp[i-1][j] (删除s[i])
dp[i][j]=dp[i][j]+dp[i-1][j] (不删除s[i])
如果只用上述式子,是会重复的。比如abcdecf,删除cde得到abcf,删除dec得到的也是abcf。
所以要删除重复计算的。从当前的i向左扫,扫到的第一个与s[i]相同的字符时处理,假设为s[k],那么dp[i][j]=dp[i][j]-dp[k-1][j-(i-k)]。


#include<iostream> #include<cstdio> #include<string.h> #include<math.h> #define maxn 1000005 using namespace std; typedef long long ll; char s[maxn]; ll dp[maxn][5]; int main() {scanf("%s",s+1);int l=strlen(s+1);dp[0][0]=1;for(int i=0;i<=l;i++){for(int j=0;j<=3;j++){if(dp[i-1][j]==0)continue;if(j<3)dp[i][j+1]+=dp[i-1][j];dp[i][j]+=dp[i-1][j];for(int k=i-1;k>=1&&i-k<=j;k--){if(s[k]==s[i]){dp[i][j]-=dp[k-1][j-i+k];break;//如果有多个,因为是从前往后推的,所以在前面减过了 }}}}printf("%lld\n",dp[l][0]+dp[l][1]+dp[l][2]+dp[l][3]);return 0; }