[KMP,DP]CF808G

给定 s s s t t t ,其中 s s s 中有 k k k?,求 s s s 补齐 ?后匹配 t t t 的最大次数。 ∣ s ∣ × ∣ t ∣ ≤ 1 0 7 |s|\times |t|\leq 10^7 s×t107


先用一组数据 H A C K HACK HACK 掉贪心做法:
(贪心只能过样例)

a?ba
aba

正确输出 1 1 1

考虑正确做法,题目中给出 ∣ t ∣ × ∣ s ∣ ≤ 1 0 7 |t|\times|s|\leq10^7 t×s107 ,暗示 O ( ∣ t ∣ ∣ s ∣ ) O(|t||s|) O(t∣∣s) 的dp

具体来讲, f [ i ] [ j ] f[i][j] f[i][j] 表示前 i i i 个数中有 j j j 个待匹配时最大匹配数。初始除了 f [ 0 ] [ 0 ] = 0 f[0][0]=0 f[0][0]=0,其余都等于 − I N F -INF INF

转移方程:

  1. f [ i ] [ j ] = f [ i − 1 ] [ j − 1 ] f[i][j]=f[i-1][j-1] f[i][j]=f[i1][j1] ,当 s [ i ] = = t [ j ] ∣ ∣ s [ i ] = = ′ ? ′ s[i]==t[j] || s[i]=='?' s[i]==t[j]∣∣s[i]==?,表示匹配上

  2. f [ i ] [ j ] = m a x ( f [ i ] [ j ] , f [ i ] [ ∣ t ∣ ] ) f[i][j]=max(f[i][j],f[i][|t|]) f[i][j]=max(f[i][j],f[i][t]),当 j j j t t t b o r d e r border border,匹配上后跳转,同时 f [ i ] [ ∣ t ∣ ] + + f[i][|t|]++ f[i][t]++

3. f [ i ] [ 0 ] = m a x ( f [ i ] [ j ] , f [ i − 1 ] [ j ] ) f[i][0]=max(f[i][j],f[i-1][j]) f[i][0]=max(f[i][j],f[i1][j]) ,表示放弃匹配

最终答案为 f [ ∣ s ∣ ] [ 0 ] f[|s|][0] f[s][0]

#include<bits/stdc++.h>
using namespace std;


char s[100005],t[100005];
int nxt[100005];
int F[50000005],slen,l;


int &f(int x,int y)
{
	return F[(x*l)+y];
}

int main()
{
	memset(F,-0x7f,sizeof(F));
	scanf("%s",s+1);
	scanf("%s",t+1);
	slen=strlen(t+1);
	for(int i=2,j=0;i<=slen;++i)
	{
		while(j && t[i]!=t[j+1])
			j=nxt[j];
		if(t[i]==t[j+1])
			++j;
		nxt[i]=j;
	}
	l=slen;
	slen=strlen(s+1);
	f(0,0)=0;
	for(int i=1;i<=slen;++i)
	{
		for(int j=1;j<=l;++j)
		{
			if(s[i]==t[j] || s[i]=='?')
				f(i,j)=f(i-1,j-1);
			if(j==l)
			{
				f(i,j)++;
				for(int k=nxt[l];k;k=nxt[k])
					f(i,k)=max(f(i,k),f(i,j));
			}
		}
		for(int j=0;j<=l;++j)
		{
			f(i,0)=max(f(i,0),max(f(i,j),f(i-1,j)));
		}
	}
	printf("%d",f(slen,0));
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值