2020年浙江理工大学新生赛 A Clytxdy

注意:本文的代码可以AC,但解释可能有误,思路仅供参考

感谢zzkgg的修正

Description
Cly成天说自己是个cdd,但这显然是假的,我们都知道clytxdy,为了验证cly到底是cdd还是txdy,请你破解以下问题。
给你一个字符串,请检查其中子序列clycddclytxdy出现次数,输出出现次数多的那个,如果出现次数一样,那当然是输出clytxdy,为了方便计算,你只需要比较出现次数对998244353取余后的结果。

Input
读入一行字符串s (1<=|s|<=1e5)

Output
输出clycddclytxdy

Sample Input
【样例1输入】
clycddcddtxdy
【样例2输入】
clytxdytxdycdd

Sample Output
【样例1输出】
clycdd
【样例2输出】
clytxdy

本题采用动态规划(DP)的方法

子串子序列有区别,子串在母串中必须是连续出现的,而子序列没有限制。为方便叙述(我懒),在本文中不作区分

(1) 定义dp[]的含义
dp[j]定义为子串(clycddclytxdy)中前 j-1 位在母串(输入的s)中出现的次数。
s1="clycdd",那么dp[6]s1s中出现的次数。

(2) 找出dp[]间的关系式
在外循环,对母串s 从前往后 遍历每一个字符,循环变量为i
在内循环,对子串s1s2 从后往前 遍历每一个字符,循环变量为j
对于子串s1[j],假设母串中已出现s1[j]的前缀(例如s1="abcb",s1[2]的前缀是"ab"),此时在母串s中找到了前缀字符串后面应该接上的s1[j],那么dp[j]=dp[j-1]
对于相同的j,如果找到了多个,自然也要算上,所以dp[j]=dp[j-1]+dp[j]
注意题目中还要对答案取模。

	for(int i=0;i<lens;i++){
		for(int j=lens1-1;j>=0;j--){
			if(s[i]==s1[j]){
				dp[j+1]=(dp[j+1]+dp[j])%998244353
			}	
		}
	}

(3) 找出初始条件
j=0时,对应的s1[j]是字串s1的开头。在这里,规定dp[0]=1。可以近似理解为s1[0]前面已找到前缀(空字符串"")。
此时如果在母串s中找到ms[0],那么dp[1]=m(dp[0]=1dp[1]=m应该是等价的)

在这里插入图片描述

#include<iostream>
using namespace std;
string s,s1="clycdd",s2="clytxdy";
long long dp1[10],dp2[10];

int main(){
	cin>>s;
	int lens=s.length();
	int lens1=s1.length(),lens2=s2.length();

	dp1[0]=1;dp2[0]=1;

	for(int i=0;i<lens;i++){
		for(int j=lens1-1;j>=0;j--){
			if(s[i]==s1[j]){
				dp1[j+1]=(dp1[j+1]+dp1[j])%998244353;
			}
		}
		
		for(int j=lens2-1;j>=0;j--){
			if(s[i]==s2[j]){
				dp2[j+1]=(dp2[j+1]+dp2[j])%998244353;
			}
		}
	}
//	cout<<dp1[lens1]<<endl<<dp2[lens2];
	if(dp1[lens1]<dp2[lens2]) cout<<"clytxdy";
	else cout<<"clycdd";
	return 0;
}

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值