【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 */
时间: 2024-10-31 22:30:04

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

HDU 2825 Wireless Password (AC自动机 + 状态压缩DP)

题目链接:Wireless Password 解析:给 m 个单词构成的集合,统计所有长度为 n 的串中,包含至少 k 个单词的方案数. AC自动机 + 状态压缩DP. DP[i][j][k]:长度为i的字符串匹配到状态j且包含k个magic word的可能字符串个数. AC代码: #include <algorithm> #include <iostream> #include <cstdio> #include <queue> #include <

hdu 4057 AC自动机+状态压缩dp

http://acm.hdu.edu.cn/showproblem.php?pid=4057 Problem Description Dr. X is a biologist, who likes rabbits very much and can do everything for them. 2012 is coming, and Dr. X wants to take some rabbits to Noah's Ark, or there are no rabbits any more.

HDU 3341 Lost&#39;s revenge AC自动机+ 状态压缩DP

题意:这个题目和HDU2457有点类似,都是AC自动机上的状态dp,题意就是给你只含有'A','T','C','G',四个字符的子串和文本串,问你文本串如何排列才可以使得文本串中包含有更多的模式串 解题思路:我们知道了 有 num[0] 个 'A', num[1] 个 ‘T’, num[2] 个 ‘C’,num[3] 个‘G’, 我们的可以知道暴力的思路就是把所有的文本串都枚举出来然后一一匹配.我们膜拜了一下春哥以后,就可以有以下思路:  把一个串的信息压缩一下,把具有同样个数字符的串看成是同一

HDU 4511 (AC自动机+状态压缩DP)

题目链接:  http://acm.hdu.edu.cn/showproblem.php?pid=4511 题目大意:从1走到N,中间可以选择性经过某些点,比如1->N,或1->2->N,但是某些段路径(注意不是某些条)是被禁止的.问从1->N的最短距离. 解题思路: AC自动机部分: 如果只是禁掉某些边,最短路算法加提前标记被禁的边即可. 但是本题是禁掉指定的路段,所以得边走边禁,需要一个在线算法. 所以使用AC自动机来压缩路段,如禁掉的路段是1->2->3,那么in

hdu 4758 Walk Through Squares(AC自动机+状态压缩DP)

题目链接:hdu 4758 Walk Through Squares 题意: 给你一个n*m的网格,现在你要从(1,1)走到(n,m),每次只能向右走或者向下走,走完后会形成一个包含R,D的序列,这个序列必须要包含题目给出的两个字符串,问有多少种方案. 题解: 由于要从(1,1)走到(n,m),所以这个形成的字符串包含R和D的数量是一定的. 现在考虑dp[u][i][j][k],表示包含两种串的组合状态,走了i个D,走了j个R,走到了k这个AC自动机的节点的方案数,然后dp一下就行了.复杂度为O

POJ 3691 (AC自动机+状态压缩DP)

题目链接:  http://poj.org/problem?id=3691 题目大意:给定N的致病DNA片段以及一个最终DNA片段.问最终DNA片段最少修改多少个字符,使得不包含任一致病DNA. 解题思路: 首先说一下AC自动机在本题中的作用. ①字典树部分:负责判断当前0~i个字符组成的串是否包含致病DNA,这部分靠字典树上的cnt标记完成. ②匹配部分:主要依赖于匹配和失配转移关系的计算,这部分非常重要,用来构建不同字符间状态压缩的转移关系(代替反人类的位运算). 这也是必须使用AC自动机而

Wireless Password - HDU 2825(ac自动机+状态压缩)

题目大意:有个人想破解他邻居的密码,他邻居告诉了一些关于这个密码的信息,并且给他一个单词集合,他用这些信息判断一下最少有多少种密码. 1->, 所有的密码都是有小写字母组成. 2->,密码的长度是 n (1<= n <=25). 3->,密码至少包含 k 种字符集里面的单词. 比如,给集合{"she", "he"},单词长度是3,最少包含两个单词的密码,很明显只能是“she”(题目表述的不清楚).   分析:因为要统计记录到达每个点时候

hdu4758AC自动机+状态压缩DP

http://acm.hdu.edu.cn/showproblem.php?pid=4758 Problem Description On the beaming day of 60th anniversary of NJUST, as a military college which was Second Artillery Academy of Harbin Military Engineering Institute before, queue phalanx is a special l

Fliptile奶牛踩瓷砖 (状态压缩,开关问题,枚举)

题目:Fliptile 题意: 给定一个M*N矩阵,有些是黑色(1表示)否则白色(0表示),每翻转一个(i,j),会使得它和它周围4个格变为另一个颜色,要求翻转最少的点,使得变为全白色的矩阵,输出这个标记了翻转点的矩阵,如果有多个最优解,输出逆字典序最小的那个矩阵,若没有解,输出IMPOSSIBLE. 题解: 参考:Fliptile POJ3279 二进制压缩枚举 解题报告 只要第一行的方案确定,后面的踩发就能确定,所以状压枚举第一行的方案 代码: /**********************