[P4965]薇尔莉特的打字机 题解

既然是博客园的第一篇题解,那就搬点有意义的吧

题目传送门

解题思路:递推

一道很好的锻炼推式子能力的题,也是本蒟蒻第一道一遍过的紫题

既然是递推,那就先定义一下状态:fi 表示在执行完第 i 个操作后,可能得到的字符串数量。

很明显,我们需要分两种情况讨论:这次操作为添加字符或退格。

先分析第一种情况,添加字符。这个时候又要分两种小情况:

当这个字符在操作中是第一次出现时,把它接在任何已有的字符串后面,都不会重复。所以 fi=fi1×2

当这个字符在操作中已经出现过时,设它上次出现处为 lst,通过手模很容易发现,在这种情况下会出现重复,而重复的次数则是 flst1,因为如果从 lsti1 的操作都没执行出来,再将第 i 次操作的字符接在后面,就相当于是接第 lst 次操作的字符在后面,而这种情况又是已经计算过的。所以 fi=fi1flst1

第二种情况,退格。我们会发现,得到的全部都是重复的字符串,只有一种情况除外:此前的操作,所有添加字符都没执行,所有退格都有执行,这个时候就会多出一种情况:原有的字符串去掉末尾长度为 k 的字串后剩下的字符串,k 为在该操作之前出现过的退格操作数。只要 k<n,就会同上所述,多出一个新的字符串。fi=fi1+1。反之就不会,fi=fi1

还需要注意的是,举个例子,原有字符串为 AB,操作uB。这个时候答案不是 4,而是3。为什么呢?因为多算了删去 B 又添加 B 的情况,还要额外再减 1。所以我们不妨设 cnti 为下一次出现 i 字符时,要减去的情况数,当前字符为 x。那么全部的递推式就是:

fi={fi1×2cntxtxufi1+1tx=uk<nfi1tx=ukn

还有一处值得一提:本人第一次写的时候,当有添加字符的操作时,把之前所有出现过的字符所产生的重复都算上了,然后就很容易地没过样例。想了一下,是因为前一个相同字符之前所产生的影响都包含在了其中,所以不用统计。

code:

点击查看代码
int n,m,cnt[27],f[maxn];
char s[maxn],t[maxn];
void solve(){
	scanf("%d%d%s%s",&n,&m,s+1,t+1);
	f[0]=1;//别忘了初始化
	for(int i=1,k=0;i<=m;i++){
		if(t[i]=='u'){
			if(k<n)f[i]=f[i-1]+1;
			else f[i]=f[i-1];
			if(k<n)cnt[s[n-k]-'A'+1]++;
			k++;
		}else{
			int x=t[i]-'A'+1;
			f[i]=f[i-1]*2%mod;
			f[i]=(f[i]-cnt[x]+mod)%mod;
			cnt[x]=f[i-1];
		}
	}
	printf("%d",f[m]);
}

花无凋零之时,爱无传达之日,爱情亘古不变,紫罗兰永世长存。

posted @   yinhee  阅读(102)  评论(1编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!

阅读目录(Content)

此页目录为空

点击右上角即可分享
微信分享提示