【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-> ...
随机推荐
- mac中添加环境变量
sudo vi /etc/paths 来编辑 paths,将环境变量添加到 paths 中. vim 是一个编辑器,另外还有几个,如:Pico,Emacs.
- 2 通过JNI混合使用Java和C++ -----> 访问数组
关于c和cpp实现native方法的一些注释: 1> 在jni.h中首先定义了C的实现方式,然后用内联函数实现了Cpp的实现方式,如下所示: const char* GetStringUTFC ...
- JAVA类与对象(六)------实例变量与类变量的区别,实例方法和类方法的区别
实例变量 实例变量声明在一个类中,但在方法.构造方法和语句块之外: 当一个对象被实例化之后,每个实例变量的值就跟着确定: 实例变量在对象创建的时候创建,在对象被销毁的时候销毁: 实例变量的值应该至少被 ...
- LeetCode-Implement strStr()-KMP
Implement strStr(). Returns the index of the first occurrence of needle in haystack, or -1 if needle ...
- AngularJS打印问题
http://stackoverflow.com/questions/22189544/print-a-div-using-javascript-in-angularjs-single-page-ap ...
- 02.Hibernate映射基础
前言:Hibernate的核心功能是根据数据库到实体类的映射,自动从数据库绑定数据到实体类.使我们操作实体类(Java对象)就能对数据库进行增.删.查.改,而不用调用JDBC API使数据操作变得简单 ...
- bzoj 2761 平衡树
裸地平衡树,只需要用到find操作 /************************************************************** Problem: U ...
- Facebook
Facebook登录为iOS Facebook的SDK为iOS提供了各种登录的经验,你的应用程序可以使用它来 验证一个人.这份文件包括了所有你需要知道,以落实Facebook登录在你的iOS应用程 ...
- map初始化定时器
init_timer(); //各种定时器的初始化 void Map::init_timer() { //auto tf = GetPlug(TimerFactory); auto tf = m_sp ...
- Centos编译安装PHP 5.5笔记
本篇是在 Centos 6.4 32bit 下编译安装 php 5.5.5 的笔记,接上篇 Centos编译安装Apache 2.4.6笔记.php 5.5.x 和 centos 源里面的 php 5 ...