ZOJ 3535 Gao the String II

搞了半天,预处理各种错。。。

先说下题目意思吧,不好理解,当时比赛的时候是以为把得到的S和每个Bi去比,Bi的每一位如果正确对上了就算得1分,结果样例直接没过,就扔掉了

后来看了解题报告和标程,发现应该是S和每个Bi去比,当Bi是S的子串时才得1分


那么我们可以用自动机来进行DP,首先预处理对于每个Ai,可以和Aj的第几位开始的后缀进行link,然后剩下的自动机DP就比较简单了

定义dp[i][j][k]表示当前长度为i,且在自动机的状态j,并且这个状态是由link Ak转移过来的,我们对于Ak的每个可行的link单词进行枚举,转移即可


代码:

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<stack>
#include<queue>
#include<vector>
#include<map>
#include<ctime>
using namespace std;
const int MAX=10000;
struct node 
{
	int next[26],fail,s;
};
node trie[MAX];
int idx,n,m,L,len[55];
char a[55][15];
vector<int>adj[55],start[55];
int dp[55][555][55];
int New()
{
	for(int i=0;i<26;i++)
		trie[idx].next[i]=-1;
	trie[idx].s=0;
	return idx++;
}
void insert(char str[])
{
	int p=0,i=0,del;
	while(str[i])
	{
		del=str[i]-'a';
		if(trie[p].next[del]==-1)
			trie[p].next[del]=New();
		p=trie[p].next[del];
		i++;
	}
	trie[p].s++;
}
void build_fail()
{
	queue<int>que;
	int fa,pre,i;
	trie[0].fail=-1;
	for(i=0;i<26;i++)
	{
		if(trie[0].next[i]!=-1)
		{
			trie[trie[0].next[i]].fail=0;
			que.push(trie[0].next[i]);
		}
		else
			trie[0].next[i]=0;
	}
	while(!que.empty())
	{
		fa=que.front();
		que.pop();
		trie[fa].s+=trie[trie[fa].fail].s;
		for(i=0;i<26;i++)
		{
			pre=trie[fa].fail;
			while(trie[pre].next[i]==-1)
				pre=trie[pre].fail;
			if(trie[fa].next[i]!=-1)
			{
				trie[trie[fa].next[i]].fail=trie[pre].next[i];
				que.push(trie[fa].next[i]);
			}
			else	
				trie[fa].next[i]=trie[pre].next[i];
		}
	}
}
void init()
{
	int i,j,k,l;
	for(i=0;i<=n;i++)
	{
		adj[i].clear();
		start[i].clear();
	}
	for(i=1;i<=n;i++)
	{
		for(j=1;j<=n;j++)
		{
			for(k=0;k<len[i]&&k<len[j];k++)
			{
				bool flag=true;
				for(l=1;l<=k;l++)
				{
					if(a[i][len[i]-k+l-1]!=a[j][l-1])
					{
						flag=false;
						break;
					}
				}
				if(flag)
				{
					adj[i].push_back(j);
					start[i].push_back(k);
				}
			}
		}
	}
	for(i=1;i<=n;i++)
	{
		adj[0].push_back(i);
		start[0].push_back(0);
	}
}
void solve()
{
	int res=0,i,j,k,l;
	memset(dp,-1,sizeof(dp));
	dp[0][0][0]=0;
	for(int ll=0;ll<L;ll++)
	{
		for(i=0;i<idx;i++)
		{
			for(j=0;j<=n;j++)
			{
				if(dp[ll][i][j]==-1)
					continue;
				int xx=adj[j].size();
				for(k=0;k<xx;k++)
				{
					int del=len[adj[j][k]]-start[j][k];
					if(ll+del>L)
						continue;
					int ns=i;
					int x=start[j][k],sum=0;
					for(int y=0;y+x<len[adj[j][k]];y++)
					{
						int tmp=a[adj[j][k]][x+y]-'a';
						ns=trie[ns].next[tmp];
						sum+=trie[ns].s;
					}
					l=adj[j][k];
					if(dp[ll+del][ns][l]<dp[ll][i][j]+sum)
					{
						dp[ll+del][ns][l]=dp[ll][i][j]+sum;
						//cout<<ll<<" "<<i<<" "<<j<<" ->"<<ll+del<<" "<<ns<<" "<<l<<" sum="<<sum<<endl;
					}
					if(res<dp[ll+del][ns][l])
						res=dp[ll+del][ns][l];
				}
			}
		}
	}
	printf("%d\n",res);
}
int main()
{
	//freopen("in.txt","r",stdin);
	//freopen("out2.txt","w",stdout);
	int i,j,k;
	//int st=clock();
	while(scanf("%d%d%d",&n,&m,&L)!=EOF)
	{
		idx=0;
		New();
		for(i=1;i<=n;i++)
		{
			scanf("%s",a[i]);
			len[i]=strlen(a[i]);
		}
		for(i=1;i<=m;i++)
		{
			scanf("%s",a[n+1]);
			insert(a[n+1]);
		}
		build_fail();
		init();
		solve();
		//int en=clock();cout<<en-st<<"ms"<<endl;	
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值