牛客练习赛60C 操作集锦(DP)

题目链接
链接:https://ac.nowcoder.com/acm/contest/4853/C
来源:牛客网

题目描述
有一款自走棋有26种操作,每种操作我们都用a,b,c,d,…,x,y,za,b,c,d,…,x,y,z的符号来代替.
现在牛牛有一个长度为nn的操作序列,他现在可以从里面拿出某些操作来组合成一个操作视频, 比如说操作序列是abcdabcd,那么操作视频就有a,b,c,d,ab,ac,ada,b,c,d,ab,ac,ad等(也就是操作序列的子序列).他现在想知道长度为kk且本质不同的操作视频有多少种.
比如对于abababab,长度为22且本质不同的结果有ab,aa,ba,bbab,aa,ba,bb。
考虑到答案可能非常大,你只需要输出在模1e9+71e9+7意义下的答案就可以了.
输入描述:
第一行两个整数n,kn,k.
第二行一个长度为nn的字符串,保证只存在小写字母.
输出描述:
一行一个整数表示长度为kk且本质不同的操作视频的个数.
示例1
输入

3 1
abc
输出
3
思路:定义dp【j】【x】表示子序列长度为j,最后一个字母为x的方案数。这里注意以下j的遍历要逆序,因为dp【j-1】【x】我们要的是上一个i的数据,如果正序的话dp【j-1】【x】求得就是当前i得数据。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod=1e9+7;
const int maxn=1e3+5;
ll dp[maxn][27];
char s[maxn];
int main()
{
	int n,k;
	scanf("%d %d",&n,&k);
	scanf("%s",s+1);
	if(k==0){
		puts("1");return 0;
	}
	for(int i=1;i<=n;++i)
	{
		for(int j=k;j>=2;--j)
		{
			if(i==n&&j==k-1) break;
			dp[j][s[i]-'a']=0;
				for(int x=0;x<26;++x)
		dp[j][s[i]-'a']=(dp[j][s[i]-'a']+dp[j-1][x])%mod;
		}
	
		dp[1][s[i]-'a']=1;
	}
	ll ans=0;
	for(int i=0;i<26;++i) ans+=dp[k][i],ans%=mod;
	printf("%lld\n",ans);
}
发布了328 篇原创文章 · 获赞 1 · 访问量 9110

猜你喜欢

转载自blog.csdn.net/qq_42479630/article/details/105185298