Lost'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] + 1);

bit[2] = (num[0] + 1) * (num[1] + 1);

bit[3] = (num[0] + 1) * (num[1] + 1) * (num[2] + 1);

这样就实现了A,B,C,D的唯一表示。

知道如何优化空间这题就变得非常简单了。

  1 #include <set>
  2 #include <map>
  3 #include <stack>
  4 #include <queue>
  5 #include <cmath>
  6 #include <ctime>
  7 #include <cstdio>
  8 #include <string>
  9 #include <vector>
 10 #include <cstring>
 11 #include <iostream>
 12 #include <algorithm>
 13 #include <unordered_map>
 14
 15 #define  pi    acos(-1.0)
 16 #define  eps   1e-9
 17 #define  fi    first
 18 #define  se    second
 19 #define  rtl   rt<<1
 20 #define  rtr   rt<<1|1
 21 #define  bug                printf("******\n")
 22 #define  mem(a, b)          memset(a,b,sizeof(a))
 23 #define  name2str(x)        #x
 24 #define  fuck(x)            cout<<#x" = "<<x<<endl
 25 #define  sfi(a)             scanf("%d", &a)
 26 #define  sffi(a, b)         scanf("%d %d", &a, &b)
 27 #define  sfffi(a, b, c)     scanf("%d %d %d", &a, &b, &c)
 28 #define  sffffi(a, b, c, d) scanf("%d %d %d %d", &a, &b, &c, &d)
 29 #define  sfL(a)             scanf("%lld", &a)
 30 #define  sffL(a, b)         scanf("%lld %lld", &a, &b)
 31 #define  sfffL(a, b, c)     scanf("%lld %lld %lld", &a, &b, &c)
 32 #define  sffffL(a, b, c, d) scanf("%lld %lld %lld %lld", &a, &b, &c, &d)
 33 #define  sfs(a)             scanf("%s", a)
 34 #define  sffs(a, b)         scanf("%s %s", a, b)
 35 #define  sfffs(a, b, c)     scanf("%s %s %s", a, b, c)
 36 #define  sffffs(a, b, c, d) scanf("%s %s %s %s", a, b,c, d)
 37 #define  FIN                freopen("../in.txt","r",stdin)
 38 #define  gcd(a, b)          __gcd(a,b)
 39 #define  lowbit(x)          x&-x
 40 #define  IO                 iOS::sync_with_stdio(false)
 41
 42
 43 using namespace std;
 44 typedef long long LL;
 45 typedef unsigned long long ULL;
 46 const ULL seed = 13331;
 47 const LL INFLL = 0x3f3f3f3f3f3f3f3fLL;
 48 const int maxn = 1e6 + 7;
 49 const int maxm = 8e6 + 10;
 50 const int INF = 0x3f3f3f3f;
 51 const int mod = 1e9 + 7;
 52
 53 int n, dp[510][11 * 11 * 11 * 11 + 10], num[5], bit[5];
 54 char buf[50];
 55
 56 int get_num(char ch) {
 57     if (ch == ‘A‘) return 0;
 58     if (ch == ‘T‘) return 1;
 59     if (ch == ‘C‘) return 2;
 60     if (ch == ‘G‘) return 3;
 61 }
 62
 63 struct Aho_Corasick {
 64     int next[510][4], fail[510], End[510];
 65     int root, cnt;
 66
 67     int newnode() {
 68         for (int i = 0; i < 4; i++) next[cnt][i] = -1;
 69         End[cnt++] = 0;
 70         return cnt - 1;
 71     }
 72
 73     void init() {
 74         cnt = 0;
 75         root = newnode();
 76     }
 77
 78     void insert(char buf[]) {
 79         int len = strlen(buf);
 80         int now = root;
 81         for (int i = 0; i < len; i++) {
 82             if (next[now][get_num(buf[i])] == -1) next[now][get_num(buf[i])] = newnode();
 83             now = next[now][get_num(buf[i])];
 84         }
 85         End[now]++;
 86     }
 87
 88     void build() {
 89         queue<int> Q;
 90         fail[root] = root;
 91         for (int i = 0; i < 4; i++)
 92             if (next[root][i] == -1) next[root][i] = root;
 93             else {
 94                 fail[next[root][i]] = root;
 95                 Q.push(next[root][i]);
 96             }
 97         while (!Q.empty()) {
 98             int now = Q.front();
 99             Q.pop();
100             End[now] += End[fail[now]];
101             for (int i = 0; i < 4; i++)
102                 if (next[now][i] == -1) next[now][i] = next[fail[now]][i];
103                 else {
104                     fail[next[now][i]] = next[fail[now]][i];
105                     Q.push(next[now][i]);
106                 }
107         }
108     }
109
110     int solve(char buf[]) {
111         int len = strlen(buf);
112         mem(num, 0);
113         for (int i = 0; i < len; ++i) num[get_num(buf[i])]++;
114         bit[0] = 1;
115         bit[1] = (num[0] + 1);
116         bit[2] = (num[0] + 1) * (num[1] + 1);
117         bit[3] = (num[0] + 1) * (num[1] + 1) * (num[2] + 1);
118         mem(dp, -1);
119         dp[0][0] = 0;
120         for (int A = 0; A <= num[0]; ++A) {
121             for (int B = 0; B <= num[1]; ++B) {
122                 for (int C = 0; C <= num[2]; ++C) {
123                     for (int D = 0; D <= num[3]; ++D) {
124                         for (int i = 0; i < cnt; ++i) {
125                             int s = A * bit[0] + B * bit[1] + C * bit[2] + D * bit[3];
126                             if (dp[i][s] == -1) continue;
127                             for (int k = 0; k < 4; ++k) {
128                                 if (k == 0 && A == num[0]) continue;
129                                 if (k == 1 && B == num[1]) continue;
130                                 if (k == 2 && C == num[2]) continue;
131                                 if (k == 3 && D == num[3]) continue;
132                                 int idx = next[i][k];
133                                 dp[idx][s + bit[k]] = max(dp[idx][s + bit[k]], dp[i][s] + End[idx]);
134                             }
135                         }
136                     }
137                 }
138             }
139         }
140         int ans = 0, status = num[0] * bit[0] + num[1] * bit[1] + num[2] * bit[2] + num[3] * bit[3];
141         for (int i = 0; i < cnt; ++i) ans = max(ans, dp[i][status]);
142         return ans;
143     }
144
145
146     void debug() {
147         for (int i = 0; i < cnt; i++) {
148             printf("id = %3d,fail = %3d,end = %3d,chi = [", i, fail[i], End[i]);
149             for (int j = 0; j < 26; j++) printf("%2d", next[i][j]);
150             printf("]\n");
151         }
152     }
153 } ac;
154
155 int main() {
156     //FIN;
157     int cas = 1;
158     while (sfi(n) && n) {
159         ac.init();
160         for (int i = 0; i < n; ++i) {
161             sfs(buf);
162             ac.insert(buf);
163         }
164         ac.build();
165         sfs(buf);
166         printf("Case %d: %d\n", cas++, ac.solve(buf));
167     }
168     return 0;
169 }

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

原文地址:https://www.cnblogs.com/qldabiaoge/p/11379448.html

时间: 2024-10-09 21:15:22

Lost's revenge HDU - 3341 AC自动机+DP(需要学会如何优雅的压缩状态)的相关文章

hdu 2296 aC自动机+dp(得到价值最大的字符串)

Ring Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 3180    Accepted Submission(s): 1033 Problem Description For the hope of a forever love, Steven is planning to send a ring to Jane with a rom

hdu 2457 AC自动机+dp

DNA repair Time Limit: 5000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 2004    Accepted Submission(s): 1085 Problem Description Biologists finally invent techniques of repairing DNA that contains segments c

DNA repair HDU - 2457 AC自动机+DP

题意: 给你N个模板串,并且给你一个文本串, 现在问你这个文本串最少需要改变几个字符才能使得它不包含任何模板串. (以上字符只由A,T,G,C构成) 题解: 刚开始做这一题的时候表示很懵逼,好像没有学过这种类型的问题. 后面仔细想想,在之前的题目中,学会了求出不包含任何模板串的方案数. 这题可以转化下,求出所有不包含任何模板串的方案中与原串最少的不同数目. 根据这个DP dp[i][j] 表示走到长度为 i 的时候,在AC自动机 j 这个节点上最多与原串不同的个数. 然后这题就变成SB题了. 1

HDU 3341 Lost&#39;s revenge AC自动机+dp

Lost's revenge Time Limit: 15000/5000 MS (Java/Others)    Memory Limit: 65535/65535 K (Java/Others)Total Submission(s): 3757    Accepted Submission(s): 1020 Problem Description Lost and AekdyCoin are friends. They always play "number game"(A bor

Hdu 3341 Lost&#39;s revenge (ac自动机+dp+hash)

题目大意: 给出很多个DNA串,每一个串的价值为1,最后给出一个长串,要你重新排列最后的串使之它所有的子串的权值和最大. 思路分析: 最先容易想到的思路就是搜!管她3721..直接一个字符一个字符的码,然后在AC自动机上判断最后的权值.TLE哟. 然后发现搜过不去,那就dp咯.再容易想到的就是dp[i][a][b][c][d] 表示此时遍历AC自动机的节点在i,然后构成了a个A,b个G,c个C,d个T的权值. 再一看内存,500*40*40*40*40...然后...就没有然后了 再想,因为它说

Lost&#39;s revenge - HDU 3341 (自动机+DP)

题目大意:先给你一些子串,然后给你一个母串,母串里面的字母可以任意调换位置,问最多这个母串经过一些位置变动最多能包含多少个子串.   分析:可以比较明显的看出来的DP,先求出来ATGC分别有多少,然后再处理,不过有个比较麻烦的地方,因为ATGC的字母数最多是40,因为不知道那种字母所以是40*40*40*40,很明显这种复杂度太高,开始使用了一次打标,把每种状态都保存下来,并且保存它的下一个状态,不过很不幸这种方法TLE了,因为找他的下一个状态不是太容易,看了大神的题解后明白,其实可以使用4种不

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,还是差点超时,代码也

hdu 2825 aC自动机+状压dp

Wireless Password Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 5640    Accepted Submission(s): 1785 Problem Description Liyuan lives in a old apartment. One day, he suddenly found that there

HDU 4518 ac自动机+数位dp

吉哥系列故事--最终数 Time Limit: 500/200 MS (Java/Others)    Memory Limit: 65535/32768 K (Java/Others) Total Submission(s): 304    Accepted Submission(s): 102 Problem Description 在2012年腾讯编程马拉松比赛中,吉哥解决了一道关于斐波那契的题目,这让他非常高兴,也更加燃起了它对数学特别是斐波那契数的热爱.现在,它又在思考一个关于斐波那契