1025 Keep at Most 100 Characters (35 分)(很用心写了!)
解题思路:
如果有真正自己做完并理解1020的那题的同学,做这题应该没有多大难度,思路几乎相同,还更好想一些,就是中间有一些证明稍微绕一点。
- 记dp[i][j]为前i个字符选j个可以组成的字符串个数,那么很容易得到状态转移方程:dp[i][j]=dp[i-1][j]+dp[i-1][j-1],对应第i个字符不选和选两个情况。
- 同时我们需要考虑这两个情况会不会重复计算?显然是会的,只要在前i-1个字符里面有和第i个字符相同的,那么选了第i个字符的字符串必然是以s[i]结尾,而不选第i个字符的字符串也可能出现以s[i]结尾的,所以我们需要找到之前所有以s[i]结尾的字符串个数,它们都会被重复计算一次。那么前i-1个字符以s[i]结尾的字符串有多少个呢?
- 找到最大的k(k<i)使得s[k]=s[i],那么dp[k-1][j-1],就是前i-1个字符中以s[i]结尾的字符串个数。有人可能会说那再前面的与s[i]相等的字符呢,不需要考虑吗?其实不难发现在k之前的情况都包含在k里面了(这其实与前文提到的“所以我们需要找到之前所有以s[i]结尾的字符串个数,它们都会被重复计算一次”是一个道理),因此我们只需要计算dp[k-1][j-1]即可。所以最后再用dp[i][j]减去dp[k-1][j-1]就是正确的dp[i][j]。
- 设置初始状态(注意每一层的dp[i][0]都是1,空字符串也是合法的一种情况,只是统计答案的时候别算上)
- 最后将最后一层的所有情况进行累加即可。
代码:
#include<bits/stdc++.h>
#include<unordered_map>
#include<unordered_set>
#define ll long long
#define pii pair<int,int>
#define pll pair<ll,ll>
#define mp make_pair
#define pb push_back
#define G 6.67430*1e-11
#define rd read()
#define pi 3.1415926535
#define pdd pair<double,double>
using namespace std;
const ll mod = 1e9 + 7;
const int MAXN = 30000005;
const int MAX2 = 300005;
inline ll read() {
ll x = 0, f = 1;
char ch = getchar();
while (ch < '0' || ch>'9') {
if (ch == '-')
f = -1;
ch = getchar();
}
while (ch >= '0' && ch <= '9') {
x = (x << 1) + (x << 3) + (ch ^ 48);
ch = getchar();
}
return x * f;
}
int dp[1005][105];
signed main()
{
string s;
cin >> s;
string t = '0' + s;
dp[0][0] = 1;
dp[1][0] = 1;
dp[1][1] = 1;
for (int i = 2; i < t.size(); i++)
{
dp[i][0] = 1;
for (int j = 1; j <= 100; j++)
{
dp[i][j] = (dp[i - 1][j] + dp[i - 1][j - 1])%mod;
for (int k = i - 1; k; k--)
{
if (t[k] == t[i])
{
dp[i][j] = (dp[i][j]- dp[k - 1][j - 1]+mod)%mod;
break;
}
}
}
}
ll sum = 0;
for (int i = 1; i <= 100; i++)
{
sum = (sum + dp[s.size()][i])%mod;
}
cout << sum;
return 0;
}