Codeforces Round #556 (Div. 1) B. Three Religions

博客给出Codeforces上题目1149B的链接,分享题解思路。判定三个字符串时贪心不好做,采用dp优化,设计状态并转移,可降维。对串append字符时做二维dp,减少字符时无需dp,时间复杂度O(2502Q),最后提及代码相关。

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

链接

https://codeforces.com/contest/1149/problem/B

题解

当时没想出来,但其实顺着当时的某个思路想下去也许能够得到正解
首先考虑给定三个字符串,我怎么判定 Y E S YES YES还是 N O NO NO
显然贪心不好做
因为 d p dp dp是可以优化的嘛,我可以一上来设计状态 f l , i , j , k f_{l,i,j,k} fl,i,j,k表示考虑了串的前 l l l个字符,能否拼凑出三个串的长度为 i , j , k i,j,k i,j,k的前缀,转移的话,就枚举最后一字符放哪个串里的。看到这是一个 b o o l bool bool类型的状态,根据经验我可以降维,那我就把最大的维 l l l放到值的位置上去, f i j k f_{ijk} fijk表示的是长度为别为 i j k ijk ijk的前缀至少用到原字符串的哪个地方
好,那么这题到这里就已经结束了
容易发现,当我对某个串 a p p e n d append append一个字符的时候,我可以只做一个二维 d p dp dp
减少一个字符的时候,甚至不需要 d p dp dp
时间复杂度 O ( 25 0 2 Q ) O(250^2Q) O(2502Q)

代码

#include <bits/stdc++.h>
#define eps 1e-8
#define iinf 0x3f3f3f3f
#define linf (1ll<<60)
#define cl(x) memset(x,0,sizeof(x))
#define mod 1000000007ll
#define maxn 100010
using namespace std;
typedef long long ll;
int read(int x=0)
{
	int c, f=1;
	for(c=getchar();!isdigit(c);c=getchar())if(c=='-')f=-f;
	for(;isdigit(c);c=getchar())x=x*10+c-48;
	return f*x;
}
int f[256][256][256], table[maxn][30], N, pos[30], l1, l2, l3, Q, str[5][300];
char s[maxn];
int main()
{
	int i, j, k, num;
	char c;
	N=read(), Q=read();
	scanf("%s",s+1);
	for(i=1;i<=N;i++)s[i]=s[i]-'a'+1;
	for(i=1;i<=26;i++)pos[i]=N+1;
	for(i=1;i<=26;i++)table[N+1][i]=N+1;
	for(i=N;~i;i--)
	{
		for(j=1;j<=26;j++)table[i][j]=pos[j];
		pos[s[i]]=i;
	}
	while(Q--)
	{
		scanf("%s",s);
		// printf("opt = %c\n",s[0]);
		if(s[0]=='+')
		{
			scanf("%d%s",&num,s);
			// printf("%lld %s\n",num,s);
			// fflush(stdout);
			c=s[0]-'a'+1;
			if(num==1)
			{
				l1++;
				str[1][l1]=c;
				for(i=0;i<=l2;i++)for(j=0;j<=l3;j++)
				{
					f[l1][i][j]=table[f[l1-1][i][j]][c];
					if(i)f[l1][i][j]=min( f[l1][i][j], table[f[l1][i-1][j]][str[2][i]]);
					if(j)f[l1][i][j]=min( f[l1][i][j], table[f[l1][i][j-1]][str[3][j]]);
				}
			}
			else if(num==2)
			{
				l2++;
				str[2][l2]=c;
				for(i=0;i<=l1;i++)for(j=0;j<=l3;j++)
				{
					f[i][l2][j]=table[f[i][l2-1][j]][c];
					if(i)f[i][l2][j]=min( f[i][l2][j], table[f[i-1][l2][j]][str[1][i]]);
					if(j)f[i][l2][j]=min( f[i][l2][j], table[f[i][l2][j-1]][str[3][j]]);
					// printf("f[%lld][%lld][%lld]=%lld\n",i,l2,j,f[i][l2][j]);
				}
			}
			else
			{
				l3++;
				str[3][l3]=c;
				for(i=0;i<=l1;i++)for(j=0;j<=l2;j++)
				{
					f[i][j][l3]=table[f[i][j][l3-1]][c];
					if(i)f[i][j][l3]=min( f[i][j][l3], table[f[i-1][j][l3]][str[1][i]]);
					if(j)f[i][j][l3]=min( f[i][j][l3], table[f[i][j-1][l3]][str[2][j]]);
				}
			}
		}
		else
		{
			scanf("%d",&num);
			if(num==1)l1--;
			if(num==2)l2--;
			if(num==3)l3--;
		}
		if(f[l1][l2][l3]<=N)printf("YES\n");
		else printf("NO\n");
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值