PAT顶级题解目录
Given a string which contains only lower case letters, how many different non-empty strings you can get if you can keep AT MOST 100 characters in the original order? (Note: The string obtained is a "sub-sequence" of the original string.)
Input Specification:
Each input file contains one test case, which is only one line containing the string whose length is no larger than 1000.
Output Specification:
Output the number of different non-empty strings if you can only keep at most 100 characters. Since the answer might be super large, you only need to output the answer modulo 1000000007.
Sample Input:
aabac
Sample Output:
19
Hint:
The strings are:
a, b, c, aa, ab, ac, ba, bc, aab, aaa, aac, aba, abc, bac, aaba, aabc, abac, aaac, and aabac.
题目大意:给出一个字符串,求这个字符串所有的子字符串(不含空字符串),这个子字符串与我们一般理解的不太一样,比如abc,ac也是他的子字符串,只要顺序一致即可,中间可以略过一些字符。
解题思路:动态规划,设一个dp二维数组,有dp[L][len],其中len为字符串的长度,L为min(len, L),有dp[i][j]表示截止前 j 位的字符串中的长度为 i 的子字符串的个数,最终结果应该为以 len-1号字符结尾,长度为0, 1, 2, ..., len-1的子字符串的总个数。
遍历的时候外层循环以子字符串的长度为变量,内层循环遍历整个字符串。
以dp[i][j]为例,截止前 j 位的字符串中的长度为 i 的子字符串应该有两种情况
1.截止前 j-1 位的字符串中的长度为 i 的子字符串的个数,即dp[i][j-1],那么产生子字符的之后不使用 j 位的字符
2.截止前 j-1 位的字符串中的长度为 i -1的子字符串的个数,即dp[i-1][j-1],那么产生子字符的之后使用 j 位的字符
关键点来了
我们以上并没有考虑重复情况!如果在计算dp[i][j]的时候,前面就已经有过s[x] == s[j],那么上述两种情况,第二种此时就不可以再加一次,因为dp[x][j]已经包含了这些字符串。所以我们用一个num数组,记录每一轮出现的每个字母结尾的次数,注意对dp[i][j]来讲,这个个数记录的是dp[i-1][j-1],因为只要记录本次产生以s[j]结尾的字符串的个数!!
代码:
#include <bits/stdc++.h>
using namespace std;
const int inf = 1000000007;
int main(){
string s;
cin >> s;
int len = s.length() + 1;
int L = min(len, 101);
vector<vector<long long>> dp(L, vector<long long>(len, 1));
for(int i = 1; i < L; ++ i){
vector<long long> num(26, 0);
num[s[i-1] - 'a'] = 1;
for(int j = i + 1; j < len; ++ j){
dp[i][j] = (dp[i][j-1] + dp[i-1][j-1] - num[s[j-1]-'a'] + inf) % inf;
num[s[j-1]-'a'] = dp[i-1][j-1];
}
}
long long ans = 0;
for(int i = 1; i < L; ++ i)
ans = (ans + dp[i][len-1]) % inf;
printf("%lld", ans);
}