时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 262144K,其他语言524288K 64bit IO Format:
%lld
题目描述
有一款自走棋有26种操作,每种操作我们都用a,b,c,d,...,x,y,z的符号来代替.
现在牛牛有一个长度为nnn的操作序列,他现在可以从里面拿出某些操作来组合成一个操作视频,
比如说操作序列是abcdabcdabcd,那么操作视频就有a,b,c,d,ab,ac,ad等(也就是操作序列的子序列).他现在想知道长度为k且本质不同的操作视频有多少种.
比如对于abab,长度为2且本质不同的结果有ab,aa,ba,bb 考虑到答案可能非常大,你只需要输出在模1e9+7意义下的答案就可以了.
输入描述:
第一行两个整数n,k 第二行一个长度为n的字符串,保证只存在小写字母.
输出描述:
一行一个整数表示长度为k且本质不同的操作视频的个数.
示例1
输入
3 1 abc
输出
3
备注:
1≤n≤1e3
0≤k≤n
题意:
给你一个长度为n的字符串,问有多有长度为k的子字符串,且不重复。
题解:
这种求子字符串数量题一般都用dp来做
dp[i][j]表示q前i个字符串中,长度为j的子字符串的数量
但是这个题是存在重复情况的,我们还要进行去重
这咋整?我们将dp从二维增加到三维,dp[i][j][k]新填一个k,k表示以什么字母结尾,(因为我们可以将az转换成数字,a对应0,b对应1,一次类推),在dp添加时我们if判断,如果当前结尾不是我们指定的字母,就不添加当前这位;如果是的话,就在前面的基础在最后一位填上这个字母。很正常(笑哭),我也快把自己讲晕了~~
不明白?
这个k就相当于是针对性的,dp[i][j][k]就是前i个字符串中选j个以k为结尾的字符数量
举例大法:n=4 m=2
abab
你会发现链接对于abab,长度为2且本质不同的结果有ab,aa,ba,bb,虽然abab的子字符串中ab出现两次,但是只统计了一次,因为在算以b(最后这个b)为结尾的时候,前面两个a算作一个a处理
代码:
#include<bits/stdc++.h> using namespace std; const int maxn=1004; int dp[maxn][maxn][30]; char a[maxn]; const int mod=1e9+7; long long sum=0; int main() { int n,m; cin>>n>>m; char ch=getchar(); cin>>a; if(m==0){ cout<<1; return 0; } for(int i=1;i<=n;i++) { dp[i][1][a[i-1]-'a']=1; for(int j=1;j<=m;j++) { for(int w=0;w<=25;w++) { if(a[i-1]-'a'==w) { for(int k=0;k<=25;k++) { dp[i][j][w]=(dp[i][j][w]+dp[i-1][j-1][k])%mod; } } else dp[i][j][w]=(dp[i][j][w]+dp[i-1][j][w])%mod; } } } for(int i=0;i<=25;i++) sum=(sum+dp[n][m][i])%mod; cout<<sum; }
注意注意:不要忘了MOD
据说还能优化,等学会了再更新
啦啦啦我又回来了
在从别人那里学习完之后
上面这个解法复杂度是O(26n^2^)
我们这次把26给省掉变成O(n^2^)
设两个数组
g[i]:在前i个字符长度为j的本质不同的子序列个数
f[i][j]:前i个字符长度为j的本质不同的子序列个数
f[i][j]=f[i-1][j-1]+f[i-1][j]
f[i-1][j-1]就是不选择s[i]
f[i-1][j]就是选择s[i]
选择的s[i]加上后有可能会重复,就需要我们先判断当前的s[i]是否用过,然后把重复的部分去掉
f [ i ] [ j ] =f[ i ] [ j ]-f[ g [ s [ i ] ] - 1 ] [ j - 1 ]
还有在加的过程中注意不断的mod
#include <bits/stdc++.h> using namespace std; #define LL long long const int mod=1e9+7; char s[100005]; LL f[1005][1005], g[30]={0}; int main() { int n, k; scanf("%d%d", &n, &k); scanf("%s", s+1); for(int i=1; i<=n; i++){ f[i-1][0]=1; for(int j=1; j<=i; j++){ f[i][j]=(f[i-1][j]+f[i-1][j-1])%mod; if(g[s[i]]){ f[i][j]-=f[g[s[i]]-1][j-1]; } f[i][j]=(f[i][j]+mod)%mod; } g[s[i]]=i; } f[n][0]=1; cout<<f[n][k]%mod<<endl; return 0; }
完毕撒花✿✿ヽ(°▽°)ノ✿