bzoj3214 [Zjoi2013]丽洁体 dp

把单词全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]);
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值