CF556(div.2) D.Three Religions

博客给出一个字符串操作问题,即对三个空串进行添加或删除字母操作,每次操作后询问能否作为给定字符串的不相交子序列。题解采用动态规划,设dp数组表示指针位置对应的最短前缀长度,每次操作更新dp,还可加入nxt数组加速,总复杂度为O(q∗2502)。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目大意

给出长度为n(n&lt;=100000)n(n&lt;=100000)n(n<=100000)的小写字母字符串sss,一开始有三个空串t1,t2,t3t_1,t_2,t_3t1,t2,t3,有q(q&lt;=1000)q(q&lt;=1000)q(q<=1000)次操作,每次操作对这三个字符串中某一个末尾添上一个小写字母或者删掉末尾的字母,每次操作之后进行一次询问,能否将这三个字符串作为sss中不相交的子序列。(保证任何时候t1,t2,t3t_1,t_2,t_3t1,t2,t3长度都不超过250)

题解

dp[i][j][k]dp[i][j][k]dp[i][j][k]表示对三个串的指针分别走到i,j,ki,j,ki,j,k时在s中对应的最短前缀的长度,如果不能匹配则为n+1n+1n+1。这样对每次操作之后更新一次dp,只需要判断当前的dp值是否超过n即可。因为每次只更新一个串,所以每次操作只需要O(2502)O(250^2)O(2502),总复杂度则为O(q∗2502)O(q*250^2)O(q2502),其中可以加入nxt数组来加速,nxt[i][j]nxt[i][j]nxt[i][j]表示在sss中第iii个字母之后的第一个字母jjj所在的位置,如果不存在则为n+1n+1n+1

代码如下

#include<bits/stdc++.h>
using namespace std;
int n,q,len[5],dp[255][255][255],nxt[100005][30];
char s[100005],t[5],d[5][255];
int main(){
	scanf("%d%d%s",&n,&q,s+1);
	for(int i=0;i<26;i++)nxt[n][i]=nxt[n+1][i]=n+1;
	for(int i=n-1;i>=0;i--){
		for(int j=0;j<26;j++){
			nxt[i][j]=nxt[i+1][j];
		}nxt[i][s[i+1]-'a']=i+1;
	}
	for(int x,i=1;i<=q;i++){
		scanf("%s%d",t,&x);
		if(*t=='-'){
			len[x]--;
		}else{
			len[x]++;
			scanf("%s",t);
			d[x][len[x]]=*t;
			for(int p1=x==1?len[x]:0;p1<=len[1];p1++){
				for(int p2=x==2?len[x]:0;p2<=len[2];p2++){
					for(int p3=x==3?len[x]:0;p3<=len[3];p3++){
						dp[p1][p2][p3]=n+1;
						if(p1)dp[p1][p2][p3]=min(dp[p1][p2][p3],nxt[dp[p1-1][p2][p3]][d[1][p1]-'a']);
						if(p2)dp[p1][p2][p3]=min(dp[p1][p2][p3],nxt[dp[p1][p2-1][p3]][d[2][p2]-'a']);
						if(p3)dp[p1][p2][p3]=min(dp[p1][p2][p3],nxt[dp[p1][p2][p3-1]][d[3][p3]-'a']);
					}
				}
			}
		}puts(dp[len[1]][len[2]][len[3]]<=n?"YES":"NO");
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值