把单词全hash出来,比ac自动机匹配方便多了。。
首先A和C直接贪心就可以了
然后可以可以根据特殊数据:每个词出现次数上限500;
每个相同的词可以对应不一样的位置,所以只需要记录在哪些位置出现过,复杂度上限是n*500
中间的匹配就用dp,由上一个转移来,注意开始词f是0,结束词f要取最小值(方便统计答案)
码(linux要len-1):
#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#include<map>
using namespace std;
char S[250005],A[250005],B[250005],C[250005];
int z1,z2,qd,zd,i,j,g[250005],lwz[250005],wz[250005],lenS,cnt,lenA,lenB,lenC,f[250005],ciA[250005],ciB[250005],ciC[250005],ciS[250005],Ccnt,Bcnt,Acnt,Scnt,ans;
vector<int>v[250005];
map<int,int>ma;
int haxi(char *ch,int qd,int zd)
{
long long ans=0,i;
for(i=qd;i<=zd;i++)ans=(ans*27+ch[i]-'a'+1)%1000000007;
return int(ans);
}
int main()
{
gets(S);
gets(A);
gets(B);
gets(C);
lenS=strlen(S)-1;lenA=strlen(A)-1;lenB=strlen(B)-1;lenC=strlen(C)-1;
z1=0;
for(i=0;i<=lenS;i++)
{
if(S[i]==' '||i==lenS)
{z2=i-1;
ciS[++Scnt]=haxi(S,z1,z2);
z1=i+1;
}
}
z1=0;
for(i=0;i<=lenA;i++)
{
if(A[i]==' '||i==lenA)
{z2=i-1;
ciA[++Acnt]=haxi(A,z1,z2);
z1=i+1;
}
}
z1=0;
for(i=0;i<=lenB;i++)
{
if(B[i]==' '||i==lenB)
{z2=i-1;
ciB[++Bcnt]=haxi(B,z1,z2);
z1=i+1;
}
}
z1=0;
for(i=0;i<=lenC;i++)
{
if(C[i]==' '||i==lenC)
{z2=i-1;
ciC[++Ccnt]=haxi(C,z1,z2);
z1=i+1;
}
}
z1=1;
for(i=1;i<=Scnt;i++)
{
if(ciA[z1]!=ciS[i])++ans;
else z1++;
if(z1>Acnt)break;
}
qd=i+1;z1=Ccnt;
for(i=Scnt;i>=1;i--)
{
if(ciC[z1]==ciS[i])--z1;
else ans++;
if(z1==0)break;
}zd=i-1;
for(i=1;i<=Bcnt;i++)
{f[i]=9999999;
if(ma[ciB[i]]==0)
ma[ciB[i]]=++cnt;
v[ma[ciB[i]]].push_back(i);
}
int nd;
f[Bcnt]=999999999;
for(i=qd;i<=zd;i++)
{
int o=ma[ciS[i]];
if(o==0)continue;
else
{
for(j=0;j<v[o].size();j++)
{
nd=v[o][j];
if(nd==Bcnt)
g[nd]=f[nd-1]+i-wz[nd-1]-1;
else g[nd]=f[nd-1]+i-wz[nd-1]-1;
if(nd==1)
f[nd]=0;
}
for(j=0;j<v[o].size();j++)
{ nd=v[o][j];
if(nd==Bcnt)
f[nd]=min(f[nd],g[nd]);else f[nd]=g[nd];
wz[nd]=i; if(nd==1){
f[nd]=0;
}
}
}
}
printf("%d",ans+f[Bcnt]);
}