JZOJ 3337. 【NOI2013模拟】wyl8899的TLE【暴力】


题目:

传送门


题意:

给出两个字符串,在 A A A串中至多修改一个字符,问这样之后其在 B B B串匹配子序列的最大长度是多少


分析:

我不想跟你多说话,并向你随手扔了个 n 2 n^2 n2暴力 . . . ... ...
然后就 A A A了,哈哈哈
想得美呢,虽然也差不多。好了,让我们回到正题, n 2 n^2 n2的暴力可能肯定是过不去,那让我们考虑下如何优化,我想到的是因为在逐字匹配的时候如果遇上了连续相同的字符,我们完全可以省略这一段的匹配,直接跳到第一个不相同的字符
g 1 g_1 g1表示 A A A串每个相同的字符要加上多少位就能到达第一个不同的字符,如 A : a a a b b c A:aaabbc A:aaabbc,那么 g 1 : 321211 g_1:321211 g1:321211 g 2 g_2 g2表示 B B B串中的,在匹配的过程中,一旦遇上了相同的,我们便可以跳到 m i n ( g 1 , g 2 ) min(g_1,g_2) min(g1,g2)


代码:

#include<cstdio>
#include<string>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<queue>
#define LL long long 
#define LZX IMS
using namespace std;
inline LL read() {
    LL d=0,f=1;char s=getchar();
    while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}
    while(s>='0'&&s<='9'){d=d*10+s-'0';s=getchar();}
    return d*f;
}   
char s1[50005],s2[50005];
int g1[50005],g2[50005];
int main()
{
	memset(g1,0x3f,sizeof(g1));memset(g2,0x3f,sizeof(g2));
	scanf("%s",s1+1);scanf("%s",s2+1);
	int l2=strlen(s2+1),l1=strlen(s1+1);
	g1[l1]=1;
	for(int i=l1-1;i;i--)
	  if(s1[i]==s1[i+1]) g1[i]=g1[i+1]+1;
	  else g1[i]=1;
	g2[l2]=1;
	for(int i=l2-1;i;i--)
	  if(s2[i]==s2[i+1]) g2[i]=g2[i+1]+1;
	  else g2[i]=1;
	int ans=0,tf,cnt,k,j;
	for(int i=1;i<=l2;i++)
	{
		if(ans==l1) break;
		tf=0;cnt=0;k=i;j=1;
		for(;j<=l1&&k<=l2;)
		{
			if(s1[j]==s2[k]) 
			{
				int giao=min(g1[j],g2[k]);
				j+=giao;k+=giao;
				cnt+=giao;
				continue;
			}
			if(s1[j]!=s2[k]&&tf) break; 
			if(s1[j]!=s2[k]&&!tf) tf=1,cnt++,j++,k++;
		}
		ans=max(ans,cnt);
	}
	cout<<ans;
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值