$f[i][j]$表示到第$i$个字符,已经删去了$j$个字符的方案数。
显然的转移:
$f[i][j] = f[i - 1][j] + f[i - 1][j - 1]$
但是这样会有重复,我们考虑什么情况会重复。
比如说:'aabab'中的'bab',我们删去'ba',得到'aab',删去'ab'得到'aab',两者是相同的
1 2 3 4 5
a a b a b
我们假设之前的每一位存的都是没有重复的方案数
就刚才的情况,我们发现当我们递推到第$5$个位置的时候,删去第三位和第四位的'ba',但是保留着第五位的'b'
那这种情况和递推到第$3$个位置的时候,保留着第$3$位的'd'是一样的
即:
$f[5][2] = f[2][0]$
$f[5][3] = f[2][1]$
减去这些重复情况,我们就能保证已经递推过来的情况中没有重复情况
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 #define ll long long 5 #define N 1000010 6 int n; 7 char s[N]; 8 int pos[220]; 9 ll f[N][4]; 10 11 int main() 12 { 13 while (scanf("%s", s + 1) != EOF) 14 { 15 memset(pos, -1, sizeof pos); 16 n = strlen(s + 1); 17 f[0][0] = 1; 18 for (int i = 1; i <= n; ++i) 19 { 20 int d = pos[s[i]]; 21 pos[s[i]] = i; 22 f[i][0] = f[i][1] = 1; 23 for (int j = 1; j < 4; ++j) 24 { 25 f[i][j] += f[i - 1][j]; 26 f[i][j + 1] = f[i - 1][j]; 27 if (d != -1 && j - i + d >= 0) 28 f[i][j] -= f[d - 1][j - i + d]; 29 } 30 } 31 printf("%lld ", f[n][0] + f[n][1] + f[n][2] + f[n][3]); 32 } 33 return 0; 34 }