【HDU3341】AC自动机状态压缩DP,或者说hash枚举DP,-------出题人卡常数都是狗!!!!!

题意:给若干个串,再给个主串,然后把主串打乱顺序,使得包含子串尽量多(一种可以有多个,两个之间可以部分重叠)。如第一组数据,ACGT,包含AC、CG、GT,三个,输出3。第二组数据A1A2A3,包含A1A2和A2A3两个“AA”,答案为2。


其实我并没有AC。我被卡常数TLE了。。。实在不想写这种没意义的东西了。


贴代码,待填坑。

#include <queue>
#include <cstdio>
#include <cstring>
#include <iostream>
#define max(a,b) (a>b?a:b)
#define N 41
#define P 505
#define M 15000// 14641
#define T 4
#define inf 0x3f3f3f3f
using namespace std;
char ttt[50];
int f[P][M],g[P][M],crs[200];
int cn[5],mul[5],ed;
struct ACAUTO
{
	int next[P][T],num[P],fail[P],cnt,stack[P];
	queue<int>q;
	void init()
	{
		while(!q.empty())q.pop();
		memset(num,0,sizeof(num));
		memset(fail,0,sizeof(fail));
	}
	void insert()
	{
		static int i,x,alp;
		x = 0;
		scanf("%s",ttt);
		for(i=0;ttt[i];i++)
		{
			alp=crs[ttt[i]];
			if(!next[x][alp])next[x][alp]=++cnt;
			x=next[x][alp];
		}
		++num[x];
	}
	bool build()
	{
		int n,i,u,v,temp;
		int tcnt=0;
		scanf("%d",&n);
		if(!n)return 0;
		init();
		for(i=1;i<=n;++i)insert();
		q.push(0);
		while(!q.empty())/*維護fail指針*/
		{
//			static int _ = 0;
//			cout << ++_ << endl;
			u=q.front(),q.pop();
			stack[++tcnt]=u;
			for(i=0;i<T;++i)if(v=next[u][i])
			{
				if(u)
				{
					temp=fail[u];
					while(temp&&!next[temp][i])temp=fail[temp];
					fail[v]=next[temp][i];

					num[v]+=num[fail[v]];
				}
				q.push(v);
			}
		}
		return 1;
	}
	void dp()
	{
		int i,j,u,v;
		int zt;
		for(u=0;u<=cnt;u++)
		{
			for(i=0;i<ed;i++)
			{
				for(j=0;j<T;j++)if(next[u][j]&&((j?i%mul[j-1]:i)/mul[j]+1)<cn[j])
				{
					v=next[u][j];
					zt=i+mul[j];
					f[v][zt]=max(f[v][zt],g[u][i]+num[v]);
				//	f[v][zt]=max(f[v][zt],f[u][i]+num[v]);
				}
			}
		}
		for(i=cnt+1;i;i--)
		{
			u=stack[i];
			v=fail[u];
		//	for(j=0;j<ed;j++)f[v][j]=max(f[v][j],f[u][j]);
			for(j=0;j<ed;j++)g[u][j]=max(g[u][j],f[u][j]),g[v][j]=max(g[v][j],g[u][j]);
		}
	}
}acauto;
void work(int cas)
{
	int i,j,k;
	scanf("%s",ttt);
	memset(cn,0,sizeof(cn));
	memset(f,0xc0,sizeof(f));
	memset(g,0xc0,sizeof(g));
	f[0][0]=g[0][0]=0;

	for(i=0;ttt[i];i++)cn[crs[ttt[i]]]++;
	for(i=0;i<T;i++)cn[i]++;
	for(mul[T-1]=1,i=T-2;i>=0;i--)mul[i]=cn[i+1]*mul[i+1];
	ed=cn[0]*cn[1]*cn[2]*cn[3];

	int ans=0,llen=strlen(ttt);
	for(i=0;i<llen;i++)
		acauto.dp();

	for(i=0;i<=acauto.cnt;i++)for(j=0;j<ed;j++)ans=max(ans,g[i][j]);
	printf("Case %d: %d\n",cas,ans);
}
int  main()
{
//	freopen("test.in","r",stdin);
	int cas=0;
	crs['A']=0,crs['C']=1,crs['G']=2,crs['T']=3;
	while(acauto.build())work(++cas);
	return 0;
}


/*2896 3065 2243 2825 3341 */


  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值