首页 > 其他 > 详细

[CSP-S模拟测试]:抛硬币(DP)

时间:2019-09-15 23:28:05      阅读:116      评论:0      收藏:0      [点我收藏+]

题目背景

小$A$和小$B$是一对好朋友,他们经常一起愉快的玩耍。最近小$B$沉迷于**师手游,天天刷本,根本无心搞学习。
但是小$B$已经入坑了几个月,却一次都没有抽到$SSR$,让他非常怀疑人生。
勤勉的小$A$为了劝说小$B$早日脱坑,认真学习,决定以抛硬币的形式让小$B$明白他是一个彻彻底底的非洲人,从而对这个游戏绝望。


题目传送门(内部题43)


输入格式

一行一个字符串$S$,字符集为所有小写字母。第二行一个数$L$如题意。


输出格式

一行一个数,表示本质不同的长度为$L$的子序列个数,答案对$998244353$取模。


样例

样例输入:

addeade
3

样例输出:

19


数据范围与提示

我们定义$|S|$为串$S$的长度。
对于$10\%$的数据,$S$只由一种字符构成。
对于另$40\%$的数据,满足$|S|,L\leqslant 15$。
对于另$20\%$的数据,满足$|S|,L\leqslant 100$。
对于全部$100\%$的数据,满足$|S|,L\leqslant 3,000$。


题解

题看起来有点虎人,但是仔细一想并不难。

依然考虑$DP$。

设$dp[i][j]$表示处理完$S$的前$i$为,长度为$j$的本质不同的子序列的个数。

如果不考虑本质不同,那么转移将是$dp[i][j]=dp[i-1][j]+dp[i-1][j-1]$。

现在来考虑减去重复的部分。

设当前位$i$的字符为$s_i$,$s_i$的上一次出现的位置是$p$,那么以$s_p$结尾的串与算重的串一一对应。

那么我们就需要减去$dp[p-1][j-1]$。

于是,最终的状态转移方程是:$dp[i][j]=dp[i-1][j]+dp[i-1][j-1]-dp[p-1][j-1]$。

时间复杂度:$\Theta({|S|}^2)$。

期望得分:$100$分。

实际得分:$100$分。


代码时刻

#include<bits/stdc++.h>
using namespace std;
char ch[3001];
int S[3001],L;
int pre[3001];
long long dp[3001][3001];
int main()
{
	scanf("%s%d",ch+1,&L);
	S[0]=strlen(ch+1);
	for(int i=1;i<=S[0];i++)
		S[i]=ch[i]-‘a‘+1;
	for(int i=1;i<=S[0];i++)
		for(int j=i-1;j;j--)
			if(S[i]==S[j]){pre[i]=j;break;}
	dp[0][0]=1;
	for(int i=1;i<=S[0];i++)
	{
		dp[i][0]=1;
		for(int j=1;j<=min(i,L);j++)
			dp[i][j]=(dp[i-1][j]+dp[i-1][j-1]-(pre[i]?dp[pre[i]-1][j-1]:0)+998244353)%998244353;
	}
	printf("%lld",dp[S[0]][L]);
	return 0;
}

rp++

[CSP-S模拟测试]:抛硬币(DP)

原文:https://www.cnblogs.com/wzc521/p/11524399.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!