给定
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∣×∣t∣≤107。
先用一组数据
H
A
C
K
HACK
HACK 掉贪心做法:
(贪心只能过样例)
a?ba
aba
正确输出 1 1 1
考虑正确做法,题目中给出 ∣ t ∣ × ∣ s ∣ ≤ 1 0 7 |t|\times|s|\leq10^7 ∣t∣×∣s∣≤107 ,暗示 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。
转移方程:
-
f [ i ] [ j ] = f [ i − 1 ] [ j − 1 ] f[i][j]=f[i-1][j-1] f[i][j]=f[i−1][j−1] ,当 s [ i ] = = t [ j ] ∣ ∣ s [ i ] = = ′ ? ′ s[i]==t[j] || s[i]=='?' s[i]==t[j]∣∣s[i]==′?′,表示匹配上
-
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[i−1][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;
}