【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循环差别这么大吗?

  1 //DP为for循环递推形式 AC
  2 #include<cstdio>
  3 #include<cstdlib>
  4 #include<cstring>
  5 #include<iostream>
  6 #include<queue>
  7 using namespace std;
  8
  9 const int N=600;
 10 struct node{
 11     int sum,fail,son[5];
 12 }a[N];
 13 queue<int> q;
 14 char s[N];
 15 int n,num,t[5],sum[5],k[5],d[15000][N];
 16 bool vis[15000][N];
 17 int maxx(int x,int y){return x>y ? x:y;}
 18 int minn(int x,int y){return x<y ? x:y;}
 19
 20 int idx(char c)
 21 {
 22     if(c==‘A‘) return 1;
 23     if(c==‘G‘) return 2;
 24     if(c==‘C‘) return 3;
 25     if(c==‘T‘) return 4;
 26 }
 27
 28 void clear(int x)
 29 {
 30     a[x].fail=a[x].sum=0;
 31     memset(a[x].son,0,sizeof(a[x].son));
 32 }
 33
 34 void trie(char *c)
 35 {
 36     int x=0,l=strlen(c);
 37     for(int i=0;i<l;i++)
 38     {
 39         int ind=idx(c[i]);
 40         if(!a[x].son[ind])
 41         {
 42             num++;
 43             clear(num);
 44             a[x].son[ind]=num;
 45         }
 46         x=a[x].son[ind];
 47     }
 48     a[x].sum++;
 49 }
 50
 51 void buildAC()
 52 {
 53     while(!q.empty()) q.pop();
 54     for(int i=1;i<=4;i++)
 55         if(a[0].son[i]) q.push(a[0].son[i]);
 56     while(!q.empty())
 57     {
 58         int x=q.front();q.pop();
 59         int fail=a[x].fail;
 60         for(int i=1;i<=4;i++)
 61         {
 62             if(a[x].son[i])
 63             {
 64                 int y=a[x].son[i],z=a[fail].son[i];
 65                 a[y].fail=z;
 66                 a[y].sum+=a[z].sum;
 67                 q.push(a[x].son[i]);
 68             }
 69             else a[x].son[i]=a[fail].son[i];
 70         }
 71     }
 72 }
 73
 74 int makeup()
 75 {
 76     return t[1]*k[1]+t[2]*k[2]+t[3]*k[3]+t[4]*k[4];
 77 }
 78
 79 int dp()
 80 {
 81     memset(d,-1,sizeof(d));
 82     d[0][0]=0;
 83     int ans=0,ss=sum[1]+sum[2]+sum[3]+sum[4];
 84     for(int l=0;l<=ss;l++)//当前选择了多少个点
 85         for(int i=0;i<=num;i++)//当前走到了第i个点
 86             for(t[1]=maxx(0,l-sum[2]-sum[3]-sum[4]);t[1]<=minn(l,sum[1]);t[1]++)//限制 最少选多少 最多选多少
 87                 for(t[2]=maxx(0,l-t[1]-sum[3]-sum[4]);t[2]<=minn(l,sum[2]);t[2]++)
 88                     for(t[3]=maxx(0,l-t[1]-t[2]-sum[4]);t[3]<=minn(l,sum[3]);t[3]++)
 89                     {
 90                         t[4]=l-t[1]-t[2]-t[3];
 91                         int now=makeup();
 92                         if(d[now][i]==-1) continue;
 93                         ans=maxx(ans,d[now][i]);
 94                         for(int j=1;j<=4;j++)
 95                         {
 96                             int y=a[i].son[j];
 97                             if(t[j]+1<=sum[j])
 98                             {
 99                                 t[j]++;
100                                 int next=makeup();
101                                 d[next][y]=maxx(d[next][y],d[now][i]+a[y].sum);
102                                 t[j]--;
103                             }
104                         }
105                     }
106     return ans;
107 }
108
109 int main()
110 {
111     freopen("a.in","r",stdin);
112     freopen("a.out","w",stdout);
113     int T=0;
114     while(1)
115     {
116         scanf("%d",&n);
117         if(!n) return 0;
118         num=0;
119         clear(0);
120         for(int i=1;i<=n;i++)
121         {
122             scanf("%s",s);
123             trie(s);
124         }
125         buildAC();
126         scanf("%s",s);
127         int mx=0,l=strlen(s);
128         memset(sum,0,sizeof(sum));
129         memset(vis,0,sizeof(vis));
130         for(int i=0;i<l;i++) sum[idx(s[i])]++;
131         for(int i=1;i<=4;i++)
132         {
133             k[i]=1;
134             for(int j=i+1;j<=4;j++)
135                 k[i]*=(sum[j]+1);
136             mx+=k[i]*sum[i];
137         }
138         printf("Case %d: %d\n",++T,dp());
139     }
140     return 0;
141 }
  1 //DP为递归形式 TLE
  2 #include<cstdio>
  3 #include<cstdlib>
  4 #include<cstring>
  5 #include<iostream>
  6 #include<queue>
  7 using namespace std;
  8
  9 const int N=600;
 10 struct node{
 11     int sum,fail,son[5];
 12 }a[N];
 13 queue<int> q;
 14 char s[N];
 15 int n,num,t[5],sum[5],k[5],d[15000][N];
 16 bool vis[15000][N];
 17 int maxx(int x,int y){return x>y ? x:y;}
 18 int minn(int x,int y){return x<y ? x:y;}
 19
 20 int idx(char c)
 21 {
 22     if(c==‘A‘) return 1;
 23     if(c==‘G‘) return 2;
 24     if(c==‘C‘) return 3;
 25     if(c==‘T‘) return 4;
 26 }
 27
 28 void clear(int x)
 29 {
 30     a[x].fail=a[x].sum=0;
 31     memset(a[x].son,0,sizeof(a[x].son));
 32 }
 33
 34 void trie(char *c)
 35 {
 36     int x=0,l=strlen(c);
 37     for(int i=0;i<l;i++)
 38     {
 39         int ind=idx(c[i]);
 40         if(!a[x].son[ind])
 41         {
 42             num++;
 43             clear(num);
 44             a[x].son[ind]=num;
 45         }
 46         x=a[x].son[ind];
 47     }
 48     a[x].sum++;
 49 }
 50
 51 void buildAC()
 52 {
 53     while(!q.empty()) q.pop();
 54     for(int i=1;i<=4;i++)
 55         if(a[0].son[i]) q.push(a[0].son[i]);
 56     while(!q.empty())
 57     {
 58         int x=q.front();q.pop();
 59         int fail=a[x].fail;
 60         for(int i=1;i<=4;i++)
 61         {
 62             if(a[x].son[i])
 63             {
 64                 int y=a[x].son[i],z=a[fail].son[i];
 65                 a[y].fail=z;
 66                 a[y].sum+=a[z].sum;
 67                 q.push(a[x].son[i]);
 68             }
 69             else a[x].son[i]=a[fail].son[i];
 70         }
 71     }
 72 }
 73
 74 int makeup(int t1,int t2,int t3,int t4)
 75 {
 76     return t1*k[1]+t2*k[2]+t3*k[3]+t4*k[4];
 77 }
 78
 79 int dp(int now,int x)
 80 {
 81     int ans=0,t1,t2,t3,t4;
 82     if(vis[now][x]) return d[now][x];
 83     t4=now%k[3];
 84     t3=((now%k[2])-(t4*k[4]))/k[3];
 85     t2=((now%k[1])-(t4*k[4]+t3*k[3]))/k[2];
 86     t1=(now-(t4*k[4]+t3*k[3]+t2*k[2]))/k[1];
 87     for(int i=1;i<=4;i++)
 88     {
 89         int y=a[x].son[i];
 90         if(!y && x) ans=maxx(ans,dp(now,0));
 91         else if(i==1 && t1>=1) ans=maxx(ans,a[y].sum+dp(makeup(t1-1,t2,t3,t4),y));
 92         else if(i==2 && t2>=1) ans=maxx(ans,a[y].sum+dp(makeup(t1,t2-1,t3,t4),y));
 93         else if(i==3 && t3>=1) ans=maxx(ans,a[y].sum+dp(makeup(t1,t2,t3-1,t4),y));
 94         else if(i==4 && t4>=1) ans=maxx(ans,a[y].sum+dp(makeup(t1,t2,t3,t4-1),y));
 95     }
 96     d[now][x]=maxx(d[now][x],ans);
 97     vis[now][x]=1;
 98     return d[now][x];
 99 }
100
101 int main()
102 {
103     freopen("a.in","r",stdin);
104     freopen("a.out","w",stdout);
105     int T=0;
106     while(1)
107     {
108         scanf("%d",&n);
109         if(!n) return 0;
110         num=0;
111         clear(0);
112         for(int i=1;i<=n;i++)
113         {
114             scanf("%s",s);
115             trie(s);
116         }
117         buildAC();
118         scanf("%s",s);
119         int mx=0,l=strlen(s);
120         memset(sum,0,sizeof(sum));
121         memset(vis,0,sizeof(vis));
122         for(int i=0;i<l;i++) sum[idx(s[i])]++;
123         for(int i=1;i<=4;i++)
124         {
125             k[i]=1;
126             for(int j=i+1;j<=4;j++)
127                 k[i]*=(sum[j]+1);
128             mx+=k[i]*sum[i];
129         }
130         // printf("%d\n",dp());
131         memset(d,0,sizeof(d));
132         printf("Case %d: %d\n",++T,dp(mx,0));
133     }
134     return 0;
135 }

【hdu3341-Lost's revenge】DP压缩+AC自动机

时间: 2024-08-25 10:30:34

【hdu3341-Lost's revenge】DP压缩+AC自动机的相关文章

Lost&#39;s revenge HDU - 3341 AC自动机+DP(需要学会如何优雅的压缩状态)

题意: 给你n个子串和一个母串,让你重排母串最多能得到多少个子串出现在重排后的母串中. 首先第一步肯定是获取母串中每个字母出现的次数,只有A T C G四种. 这个很容易想到一个dp状态dp[i][A][B][C][D] 表示在AC自动机 i 这个节点上,用了A个A,B个T,C个C,D个G. 然后我算了一下内存,根本开不下这么大的内存. 看了网上题解,然后用通过状压把,A,B,C,D压缩成一维. 这个状压就是通过进制实现需要实现唯一表示 bit[0] = 1; bit[1] = (num[0]

[dp专题] AC自动机与状态压缩dp的结合

最近做到好几道关于AC自动机与状态压缩dp的结合的题,这里总结一下. 题目一般会给出m个字符串,m不超过10,然后求长度为len并且包含特定给出的字符串集合的字符串个数. 以HDU 4758为例: 把题意抽象为:给出两个字符串,且只包含两种字符 'R'.'D',现在求满足下列条件的字符串个数:字符串长度为(m+n),其中包含n个'D',m个'R'. 如果不用AC自动机来做,这道题还真没法做了,因为不管怎样都找不到正确的dp状态转移方程. 而如果引入AC自动机,把在AC自动机上的结点当做dp的一个

ZOJ 3494 BCD Code (数位DP,AC自动机)

题意: 将一个整数表示成4个bit的bcd码就成了一个01串,如果该串中出现了部分病毒串,则是危险的.给出n个病毒串(n<=100,长度<21),问区间[L,R]中有几个数字是不含病毒串的(结果需要取模)?(0<L<=R<=10200) 思路: 区间非常大,怎样暴力统计都是不科学的.首先确定状态,按传统,一维必定是位数,二维就是压缩的状态了,如果长度为20个bit的话,200*104万的数组是不行的.类似多模式串匹配问题,病毒串可以构建成AC自动机,那么每个点可以代表一个独立

UVA 11468(Substring-AC自动机上dp)[Template:AC自动机]

Substring Given a set of pattern strings, and a text, you have to find, if any of the pattern is a substring of the text. If any of the pattern string can be found in text, then print "yes", otherwise "no" (without quotes). But, unfort

HDOJ 题目4787 GRE Words Revenge(在线ac自动机,离线也可做)

GRE Words Revenge Time Limit: 20000/10000 MS (Java/Others)    Memory Limit: 327680/327680 K (Java/Others) Total Submission(s): 1570    Accepted Submission(s): 352 Problem Description Now Coach Pang is preparing for the Graduate Record Examinations as

【AC自动机】【状压dp】hdu2825 Wireless Password

f(i,j,S)表示当前字符串总长度为i,dp到AC自动机第j个结点,单词集合为S时的方案数. 要注意有点卡常数,注意代码里的注释. #include<cstdio> #include<cstring> #include<queue> using namespace std; queue<int>q; #define MOD 20090717; int child[111][26],fail[111],size,f[30][111][1100],tag[11

转自kuangbin的AC自动机(赛前最后一博)

有了KMP和Trie的基础,就可以学习神奇的AC自动机了.AC自动机其实就是在Trie树上实现KMP,可以完成多模式串的匹配.           AC自动机 其实 就是创建了一个状态的转移图,思想很重要.           推荐的学习链接: http://acm.uestc.edu.cn/bbs/read.php?tid=4294 http://blog.csdn.net/niushuai666/article/details/7002823 http://hi.baidu.com/nial

HDU3341 Lost&#39;s revenge(AC自动机+DP)

题目是给一个DNA重新排列使其包含最多的数论基因. 考虑到内存大概就只能这么表示状态: dp[i][A][C][G][T],表示包含各碱基个数为ACGT且当前后缀状态为自动机第i的结点的字符串最多的数论基因数 其中ACGT可以hash成一个整数(a*C*G*T+c*G*T+g*T+T),这样用二维数组就行了,而第二维最多也就11*11*11*11个. 接下来转移依然是我为人人型,我是丢进一个队列,用队列来更新状态的值. 这题果然挺卡常数的,只好手写队列,最后4500msAC,还是差点超时,代码也

【HDU3341】 Lost&#39;s revenge (AC自动机+状压DP)

Lost's revenge Time Limit: 5000MS Memory Limit: 65535KB 64bit IO Format: %I64d & %I64u Description Lost and AekdyCoin are friends. They always play "number game"(A boring game based on number theory) together. We all know that AekdyCoin is t