【hdu3341-Lost's revenge】DP压缩+AC自动机
题意:给定只含有A、G、C、T的n个模板串,一个文本串,文本串任意两个字母可互换位置,问最多能匹配多少个模板串。
注意:匹配同一个模板串匹配了两次,ans+=2;(可重复)
题解:
原本想到一个简单dp : 开一个数组d[t1][t2][t3][t4][x],t1~t4分别表示4个字母各有多少个,x表示当前位置。
然后这个数组为40*40*40*40*600,各种爆空间。
后来才知道要用压缩。。。
比如ACGT分别有5,6,7,8个。那t1为6进制,可以放0~5,t2为7进制……
然后类比10进制,把它压成一个10进制的数,这个数最大是11*11*11*11=14641.
压缩的原理:

我打了两个程序,dp一个用了递归,一个用了for循环,递归那个一直超时,for那个就A了。递归跟for循环差别这么大吗?
//DP为for循环递推形式 AC
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<queue>
using namespace std; const int N=;
struct node{
int sum,fail,son[];
}a[N];
queue<int> q;
char s[N];
int n,num,t[],sum[],k[],d[][N];
bool vis[][N];
int maxx(int x,int y){return x>y ? x:y;}
int minn(int x,int y){return x<y ? x:y;} int idx(char c)
{
if(c=='A') return ;
if(c=='G') return ;
if(c=='C') return ;
if(c=='T') return ;
} void clear(int x)
{
a[x].fail=a[x].sum=;
memset(a[x].son,,sizeof(a[x].son));
} void trie(char *c)
{
int x=,l=strlen(c);
for(int i=;i<l;i++)
{
int ind=idx(c[i]);
if(!a[x].son[ind])
{
num++;
clear(num);
a[x].son[ind]=num;
}
x=a[x].son[ind];
}
a[x].sum++;
} void buildAC()
{
while(!q.empty()) q.pop();
for(int i=;i<=;i++)
if(a[].son[i]) q.push(a[].son[i]);
while(!q.empty())
{
int x=q.front();q.pop();
int fail=a[x].fail;
for(int i=;i<=;i++)
{
if(a[x].son[i])
{
int y=a[x].son[i],z=a[fail].son[i];
a[y].fail=z;
a[y].sum+=a[z].sum;
q.push(a[x].son[i]);
}
else a[x].son[i]=a[fail].son[i];
}
}
} int makeup()
{
return t[]*k[]+t[]*k[]+t[]*k[]+t[]*k[];
} int dp()
{
memset(d,-,sizeof(d));
d[][]=;
int ans=,ss=sum[]+sum[]+sum[]+sum[];
for(int l=;l<=ss;l++)//当前选择了多少个点
for(int i=;i<=num;i++)//当前走到了第i个点
for(t[]=maxx(,l-sum[]-sum[]-sum[]);t[]<=minn(l,sum[]);t[]++)//限制 最少选多少 最多选多少
for(t[]=maxx(,l-t[]-sum[]-sum[]);t[]<=minn(l,sum[]);t[]++)
for(t[]=maxx(,l-t[]-t[]-sum[]);t[]<=minn(l,sum[]);t[]++)
{
t[]=l-t[]-t[]-t[];
int now=makeup();
if(d[now][i]==-) continue;
ans=maxx(ans,d[now][i]);
for(int j=;j<=;j++)
{
int y=a[i].son[j];
if(t[j]+<=sum[j])
{
t[j]++;
int next=makeup();
d[next][y]=maxx(d[next][y],d[now][i]+a[y].sum);
t[j]--;
}
}
}
return ans;
} int main()
{
freopen("a.in","r",stdin);
freopen("a.out","w",stdout);
int T=;
while()
{
scanf("%d",&n);
if(!n) return ;
num=;
clear();
for(int i=;i<=n;i++)
{
scanf("%s",s);
trie(s);
}
buildAC();
scanf("%s",s);
int mx=,l=strlen(s);
memset(sum,,sizeof(sum));
memset(vis,,sizeof(vis));
for(int i=;i<l;i++) sum[idx(s[i])]++;
for(int i=;i<=;i++)
{
k[i]=;
for(int j=i+;j<=;j++)
k[i]*=(sum[j]+);
mx+=k[i]*sum[i];
}
printf("Case %d: %d\n",++T,dp());
}
return ;
}
//DP为递归形式 TLE
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<queue>
using namespace std; const int N=;
struct node{
int sum,fail,son[];
}a[N];
queue<int> q;
char s[N];
int n,num,t[],sum[],k[],d[][N];
bool vis[][N];
int maxx(int x,int y){return x>y ? x:y;}
int minn(int x,int y){return x<y ? x:y;} int idx(char c)
{
if(c=='A') return ;
if(c=='G') return ;
if(c=='C') return ;
if(c=='T') return ;
} void clear(int x)
{
a[x].fail=a[x].sum=;
memset(a[x].son,,sizeof(a[x].son));
} void trie(char *c)
{
int x=,l=strlen(c);
for(int i=;i<l;i++)
{
int ind=idx(c[i]);
if(!a[x].son[ind])
{
num++;
clear(num);
a[x].son[ind]=num;
}
x=a[x].son[ind];
}
a[x].sum++;
} void buildAC()
{
while(!q.empty()) q.pop();
for(int i=;i<=;i++)
if(a[].son[i]) q.push(a[].son[i]);
while(!q.empty())
{
int x=q.front();q.pop();
int fail=a[x].fail;
for(int i=;i<=;i++)
{
if(a[x].son[i])
{
int y=a[x].son[i],z=a[fail].son[i];
a[y].fail=z;
a[y].sum+=a[z].sum;
q.push(a[x].son[i]);
}
else a[x].son[i]=a[fail].son[i];
}
}
} int makeup(int t1,int t2,int t3,int t4)
{
return t1*k[]+t2*k[]+t3*k[]+t4*k[];
} int dp(int now,int x)
{
int ans=,t1,t2,t3,t4;
if(vis[now][x]) return d[now][x];
t4=now%k[];
t3=((now%k[])-(t4*k[]))/k[];
t2=((now%k[])-(t4*k[]+t3*k[]))/k[];
t1=(now-(t4*k[]+t3*k[]+t2*k[]))/k[];
for(int i=;i<=;i++)
{
int y=a[x].son[i];
if(!y && x) ans=maxx(ans,dp(now,));
else if(i== && t1>=) ans=maxx(ans,a[y].sum+dp(makeup(t1-,t2,t3,t4),y));
else if(i== && t2>=) ans=maxx(ans,a[y].sum+dp(makeup(t1,t2-,t3,t4),y));
else if(i== && t3>=) ans=maxx(ans,a[y].sum+dp(makeup(t1,t2,t3-,t4),y));
else if(i== && t4>=) ans=maxx(ans,a[y].sum+dp(makeup(t1,t2,t3,t4-),y));
}
d[now][x]=maxx(d[now][x],ans);
vis[now][x]=;
return d[now][x];
} int main()
{
freopen("a.in","r",stdin);
freopen("a.out","w",stdout);
int T=;
while()
{
scanf("%d",&n);
if(!n) return ;
num=;
clear();
for(int i=;i<=n;i++)
{
scanf("%s",s);
trie(s);
}
buildAC();
scanf("%s",s);
int mx=,l=strlen(s);
memset(sum,,sizeof(sum));
memset(vis,,sizeof(vis));
for(int i=;i<l;i++) sum[idx(s[i])]++;
for(int i=;i<=;i++)
{
k[i]=;
for(int j=i+;j<=;j++)
k[i]*=(sum[j]+);
mx+=k[i]*sum[i];
}
// printf("%d\n",dp());
memset(d,,sizeof(d));
printf("Case %d: %d\n",++T,dp(mx,));
}
return ;
}
【hdu3341-Lost's revenge】DP压缩+AC自动机的更多相关文章
- Lost's revenge HDU - 3341 AC自动机+DP(需要学会如何优雅的压缩状态)
题意: 给你n个子串和一个母串,让你重排母串最多能得到多少个子串出现在重排后的母串中. 首先第一步肯定是获取母串中每个字母出现的次数,只有A T C G四种. 这个很容易想到一个dp状态dp[i][A ...
- ZOJ 3494 BCD Code (数位DP,AC自动机)
题意: 将一个整数表示成4个bit的bcd码就成了一个01串,如果该串中出现了部分病毒串,则是危险的.给出n个病毒串(n<=100,长度<21),问区间[L,R]中有几个数字是不含病毒串的 ...
- 【HDOJ5955】Guessing the Dice Roll(概率DP,AC自动机,高斯消元)
题意: 有n个人,每个人有一个长为L的由1~6组成的数串,现在扔一个骰子,依次记录扔出的数字,如果当前扔出的最后L个数字与某个人的数串匹配,那么这个人就算获胜,现在问每个人获胜的概率是多少. n,l& ...
- 计蒜客-蒜场抽奖(AC自动机+状态压缩DP)
题解:题意不再说了,题目很清楚的. 思路:因为N<=10,所以考虑状态压缩 AC自动机中 val[1<<i]: 表示第i个字符串.AC自动机中fail指针是指当前后缀在其他串里面所能 ...
- 【AC自动机】【状压dp】hdu2825 Wireless Password
f(i,j,S)表示当前字符串总长度为i,dp到AC自动机第j个结点,单词集合为S时的方案数. 要注意有点卡常数,注意代码里的注释. #include<cstdio> #include&l ...
- 【原创】AC自动机小结
有了KMP和Trie的基础,就可以学习神奇的AC自动机了.AC自动机其实就是在Trie树上实现KMP,可以完成多模式串的匹配. AC自动机 其实 就是创建了一个状态的转移图,思想很 ...
- 转自kuangbin的AC自动机(赛前最后一博)
有了KMP和Trie的基础,就可以学习神奇的AC自动机了.AC自动机其实就是在Trie树上实现KMP,可以完成多模式串的匹配. AC自动机 其实 就是创建了一个状态的转移图,思想很 ...
- 【AC自动机&&Trie图】积累
以前KMP和后缀系列(主要是后缀数组,后缀自动机),都刷了一定数量的题,但是对于AC自动机,却有些冷落,罪过. 但是我感觉,在蓝桥杯比赛中AC自动机出现的概率比后缀系列大,简单的会考匹配,稍难一点会考 ...
- HDU 4511 (AC自动机+状态压缩DP)
题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=4511 题目大意:从1走到N,中间可以选择性经过某些点,比如1->N,或1->2-> ...
随机推荐
- 27.some company's Spi Flash chip replace altera epcsxxx
由于altera公司的epcsxxx芯片比较贵,所以一般用其它公司的spi flash芯片代替也可以.据AlteraFAE描述:“EPCS器件也是选用某家公司的SPIFlash,只是中间经过Alter ...
- OpenGL学习笔记之配置OpenGL
OpenGL是计算机图形学领域的一门入门语言,OpenGL开发库的一些文件在官网上可以下载到.里面包含三个文件,如下: 1.把在OpenGL开发库中LIB(库文件)glut.lib和glut32.li ...
- Liunx0000(初步认识)
都要放假了,学习一下吧,毕竟还有课设,虽然我真的懒得看Linux,不想接触这破玩意!各应人的东西! 一.发展趋势 1\无操作系统阶段20s60 2\简单操作系统阶段 3\试试操作系统阶段 4\面向In ...
- asp.net自带的异步刷新控件使用
一直都是使用jquery的$.ajax,由于刚刚加入的公司是用asp.net的,webform与之前的ajax加在一起显得很混乱,后来发现asp.net已经封装了一下ajax功能,就查了一下,并且做了 ...
- linux 负载 待读
相关文章: 理解 Linux 的处理器负载均值(翻译)
- php大文件下载
<?php header("Content-Type:text/html;charset:utf-8"); //class FileDownServer{ //$file_n ...
- MVC4 网站发布(整理 + 部分转载 + 部分问题收集和解决方案)
网站发布步骤: 这部分是转载文章 在此标明出处,以前有文章是转的没标明的请谅解,因为有些已经无法找到出处,或者与其它原因. 如有冒犯请联系本人,或删除,或标明出处. 因为好的文章,以前只想收藏,但连接 ...
- ASP.NET MVC 如何在一个同步方法(非async)方法中等待async方法
问题 首先,在ASP.NET MVC 环境下对async返回的Task执行Wait()会导致线程死锁.例: public ActionResult Asv2() { //dead lock var t ...
- 【Python】网络编程
1.TCP编程 2.SocketServer模块 3.Twisted框架 4.UDP编程 1.TCP编程--TCP是面向连接的,其一般的设计如下: # encoding:utf-8 ''' Creat ...
- matrix_last_acm_1
password 123 A http://acm.hust.edu.cn/vjudge/contest/view.action?cid=96950#problem/A 题意:n个数初始ai,m次操作 ...