1025 Keep at Most 100 Characters (35 分)(C++)

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);
} 

 

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值