题意
由小写英文字母组成的长度为n的一个字符串,求不相同的长度为k的子串的数量对1e9+7取模。
思路
正难则反
正难则反,我们求所有不同的子串,不如把所有子串的数量求出来再减掉所以相同的子串数量。
若不去重求所有长度为k的子串的数量,则可由推出到第个数为止长度为的子串数量。不难理解,代表的是到第个数取了个数再加上第s[i]个数构成了个数。
本题的难点在于如何去重。我们观察一个字符串。
打个简单的表让大家看一下
发现以结尾的长度的字符串会在中计算一次以为结尾的子串,而中又会计算一次以为结尾的子串,那么就重复计算了前面的那部分以为结尾的子串,显然后者包括前者且大于等于前者。
所以这里要用到来记录上一个所在的位置,当时,即上一个存在时,及时的减去上一个以
坑点:注意k为0时答案为1(出题人说的),注意初始化。
#include<bits/stdc++.h> using namespace std; typedef long long ll; typedef pair<int,int>P; const double eps = 1e-8; const int NINF = 0xc0c0c0c0; const int INF = 0x3f3f3f3f; const ll mod = 1e9 + 7; const ll maxn = 1e6 + 5; const int N = 1e3+5; ll n,k,pre[N],f[N][N]; char s[N]; int main(){ ios::sync_with_stdio(false); cin.tie(0); cin>>n>>k; cin>>s+1; f[0][0]=1; for(int i=1;i<=n;i++){ f[i][0]=1; for(int j=1;j<=i;j++){ f[i][j]=f[i-1][j]+f[i-1][j-1]; if(pre[s[i]]) f[i][j]-=f[pre[s[i]]-1][j-1]; f[i][j]%=mod; } pre[s[i]]=i; } cout<<(f[n][k]+mod)%mod<<'\n'; return 0; }