标签:
题目链接:Lost‘s revenge
解析:n个模式串,一个目标串。问目标串通过任意次交换字符最多能包含的模式串个数。(允许重叠)
字符最长是40
只需要记录ACGT出现的次数。
如果使用5维数组,显然超内存了。
假设ACGT的总数分别为num[0],num[1],num[2],num[3]
那么对于ACGT的数量分别为ABCD的状态可以记录为: (网上大神讲的,至今还没弄明白。。。求指教)
A*(num[1]+1)*(num[2]+1)*(num[3]+1) + B*(num[2]+1)*(num[3]+1)+ C*(num[3]+1) +D
这样的状态最大就是11*11*11*11
复杂度也可以承受了。
字符串可能有重复的,用int来记录数量
AC代码:
#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;
const int INF = 0x3f3f3f3f;
struct Trie{
int next[510][4], fail[510], end[510];
int root, L;
int newnode(){
for(int i=0; i<4; i++) next[L][i] = -1;
end[L++] = 0;
return L-1;
}
void init(){
L = 0;
root = newnode();
}
int getch(char ch){
if(ch == 'A') return 0;
if(ch == 'C') return 1;
if(ch == 'G') return 2;
return 3;
}
void insert(char buf[]){
int len = strlen(buf);
int now = root;
for(int i=0; i<len; i++){
if(next[now][getch(buf[i])] == -1)
next[now][getch(buf[i])] = newnode();
now = next[now][getch(buf[i])];
}
end[now] ++;
}
void build(){
queue<int> Q;
fail[root] = root;
for(int i=0; i<4; i++)
if(next[root][i] == -1) next[root][i] = root;
else{
fail[ next[root][i] ] = root;
Q.push(next[root][i]);
}
while(!Q.empty()){
int now = Q.front();
Q.pop();
end[now] += end[ fail[now] ]; //!!!
for(int i=0; i<4; i++)
if(next[now][i] == -1) next[now][i] = next[ fail[now] ][i];
else{
fail[ next[now][i] ] = next[ fail[now] ][i];
Q.push(next[now][i]);
}
}
}
int dp[510][11*11*11*11+5];
int bit[4];
int num[4];
int solve(char buf[]){
int len = strlen(buf);
memset(num, 0, sizeof(num));
for(int i=0; i<len; i++) num[ getch(buf[i]) ] ++;
bit[0] = (num[1] + 1) * (num[2] + 1) * (num[3] + 1);
bit[1] = (num[2] + 1) * (num[3] + 1);
bit[2] = (num[3] + 1);
bit[3] = 1;
memset(dp, -1, sizeof(dp));
dp[root][0] = 0;
for(int A=0; A<=num[0]; A++)
for(int B=0; B<=num[1]; B++)
for(int C=0; C<=num[2]; C++)
for(int D=0; D<=num[3]; D++){
int s = A*bit[0] + B*bit[1] + C*bit[2] + D*bit[3];
for(int i=0; i<L; i++)
if(dp[i][s] >= 0){
for(int k=0; k<4; k++){
if(k == 0 && A == num[0]) continue;
if(k == 1 && B == num[1]) continue;
if(k == 2 && C == num[2]) continue;
if(k == 3 && D == num[3]) continue;
dp[ next[i][k] ][s+bit[k]] = max(dp[ next[i][k] ][s+bit[k]], dp[i][s] + end[ next[i][k] ]);
}
}
}
int ans = 0;
int status = num[0]*bit[0] + num[1]*bit[1] + num[2]*bit[2] + num[3]*bit[3];
for(int i=0; i<L; i++)
ans = max(ans, dp[i][status]);
return ans;
}
};
char buf[50];
Trie ac;
int main(){
#ifdef sxk
freopen("in.txt", "r", stdin);
#endif // sxk
int n;
int kase = 0;
while(scanf("%d", &n) == 1 && n){
ac.init();
for(int i=0; i<n; i++){
scanf("%s", buf);
ac.insert(buf);
}
ac.build();
scanf("%s", buf);
printf("Case %d: %d\n", ++kase, ac.solve(buf));
}
return 0;
}
版权声明:本文为sxk原创文章,转载请附加本文链接^_^
HDU 3341 Lost's revenge (AC自动机 + DP)
标签:
原文地址:http://blog.csdn.net/u013446688/article/details/47748197