bzoj3075[Usaco2013]Necklace

题目链接:bzoj3075

题目大意:

给你一个长度为n的字符串A,再给你一个长度为m的字符串B,求至少在A中删去多少个字符才能使得B不是A的子串。注:该题只读入A和B,不读入长度,先读入A,再读入B。数据保证A和B中只含小写字母。


题解:

AC自动机+DP

f[i][j]表示A串搞到第i位,树上走到j所能得到的串的最大长度。

首先按B串建树,拿A来走。对于A串中的一个字符有两种选择,删与不删。如果删,那么树上的位置仍与当前一样;如果不删,就走。。注意判断一下当前节点合不合法就是了。

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<queue>
#include<iostream>
#include<algorithm>
using namespace std;
#define maxm 1010

struct node
{
	int son[26],fail;bool bk;
}tr[maxm];
int len,rt,l1,l2,f[maxm*10][maxm];
char s1[maxm*10],s2[maxm];
int new_node()
{
	len++;
	memset(tr[len].son,0,sizeof(tr[len].son));
	tr[len].fail=0;tr[len].bk=false; 
	return len;
}
void bt()
{
	int now=rt,i;
	for (i=0;i<l2;i++)
	{
		int x=s2[i]-'a';
		if (!tr[now].son[x]) tr[now].son[x]=new_node();
		now=tr[now].son[x];
	}
	tr[now].bk=true;
}
queue<int> q;
void build_AC()
{
	int i;
	for (i=0;i<26;i++)
	 if (tr[rt].son[i])
	 {
		 tr[tr[rt].son[i]].fail=rt;
		 q.push(tr[rt].son[i]);
	 }else tr[rt].son[i]=rt;
	while (!q.empty())
	{
		int x=q.front();q.pop();
		int y=tr[x].fail;
		for (i=0;i<26;i++)
		  if (tr[x].son[i])
		  {
			  if (tr[y].son[i]) tr[tr[x].son[i]].fail=tr[y].son[i];
			  else tr[tr[x].son[i]].fail=rt;
			  q.push(tr[x].son[i]);
		  }else tr[x].son[i]=tr[y].son[i];
	}
}
int mymax(int x,int y) {return (x>y)?x:y;}
int main()
{
	//freopen("a.in","r",stdin);
	//freopen("a.out","w",stdout);
	int i,j;
	len=0;rt=new_node();
	gets(s1);l1=strlen(s1);
	gets(s2);l2=strlen(s2);
	bt();build_AC();
	memset(f,-1,sizeof(f));
	f[0][rt]=0;f[0][tr[rt].son[s1[0]-'a']]=1;
	for (i=0;i<l1-1;i++)
	 for (j=1;j<=len;j++)
	  if (f[i][j]!=-1)
	  {
		  int x=s1[i+1]-'a';
		  int y=tr[j].son[x];
		  if (!tr[y].bk) f[i+1][y]=mymax(f[i+1][y],f[i][j]+1);
		  if (!tr[j].bk) f[i+1][j]=mymax(f[i+1][j],f[i][j]);
	  }
	int ans=-1;
	for (i=1;i<=len;i++)
	  if (f[l1-1][i]!=-1 && !tr[i].bk) ans=mymax(ans,f[l1-1][i]);
	printf("%d\n",l1-ans);
	return 0;
}


posted @ 2017-02-13 13:56  OxQ  阅读(175)  评论(0编辑  收藏  举报