给定一个全部由小写英文字母组成的字符串,允许你至多删掉其中 3 个字符,结果可能有多少种不同的字符串?
输入格式:
输入在一行中给出全部由小写英文字母组成的、长度在区间 [4,?106] 内的字符串。
输出格式:
在一行中输出至多删掉其中 3 个字符后不同字符串的个数。
输入样例:
ababcc
输出样例:
25
提示:
删掉 0 个字符得到 “ababcc”。
删掉 1 个字符得到 “babcc”, “aabcc”, “abbcc”, “abacc” 和 “ababc”。
删掉 2 个字符得到 “abcc”, “bbcc”, “bacc”, “babc”, “aacc”, “aabc”, “abbc”, “abac” 和 “abab”。
删掉 3 个字符得到 “abc”, “bcc”, “acc”, “bbc”, “bac”, “bab”, “aac”, “aab”, “abb” 和 “aba”。
分析:一个简单的动态规划题~使用dp[i][j]表示前i个字符串在删除j个字符的情况下能取到多少种情况。由于第i个字符只有删除以及不能删除两种情况,可以得到dp[i][j] = dp[i – 1][j](第i个字符不删,前i-1个字符删除掉j个再加上当前字符能取到的个数) + dp[i – 1][ j – 1](第i个字符删了,前i-1个字符删除掉j-1个能取到的个数)~注意可能存在的重复情况,如liuchuo在dp[6][3]时删除下标为3、4、5的”uch”后得到字符串的与删除下标为4、5、6的”chu”后得到的字符串都为”liu”,所以需要记录当前(下标为i)字符上一次出现的位置last(存在vis数组中),并判断i与last的差是否大于等于目前的j,如果更多的话,就已经不可能受到影响了,故需要减去dp[last – 1][j – (i – last)]的数量。 最后将所有删减情况加起来,得到最终答案~
#include <bits/stdc++.h>
using namespace std;
string s;
long long dp[1000001][4], vis[128], last;
int main() {
cin >> s;
for (int i = 0; i <= s.size(); i++) dp[i][0] = 1;
for (int i = 1; i <= s.size(); i++) {
last = vis[s[i - 1]];
vis[s[i - 1]] = i;
for (int j = 1; j <= 3; j++) {
dp[i][j] = dp[i - 1][j] + dp[i - 1][j - 1];
if (last && j - (i - last) >= 0) dp[i][j] -= dp[last - 1][j - (i - last)];
}
}
cout << dp[s.size()][0] + dp[s.size()][1] + dp[s.size()][2] + dp[s.size()][3];
return 0;
}
|