题目大意:
就是现在给出n个字符串(n <= 10), 只包含ACGT字符, 当其中第个串出现的时候会带来权值w[i], 然后现在要写一个长度为m的串, 问最大权值为多少
如果为负数就输出那个字符串
大致思路:
就是明显的AC自动机上的DP, 建立好AC自动机后, 用dp[i][j][k]表示当前长度为i , 在AC自动机的点 j, 装药表示的包含状态为k的方案是否可行, 初始化dp[0][0][0] = true
状态转移方程为dp[i][next[j][c]][k | end[next[j][c]]] |= dp[i - 1][j][k]
内存的话滚动一下数组就好了, 没什么大的难度
代码如下:
Result : Accepted Memory : 2332 KB Time : 450 ms
/* * Author: Gatevin * Created Time: 2015/5/14 14:48:58 * File Name: Rin_Tohsaka.cpp */ #include<iostream> #include<sstream> #include<fstream> #include<vector> #include<list> #include<deque> #include<queue> #include<stack> #include<map> #include<set> #include<bitset> #include<algorithm> #include<cstdio> #include<cstdlib> #include<cstring> #include<cctype> #include<cmath> #include<ctime> #include<iomanip> using namespace std; const double eps(1e-8); typedef long long lint; #define foreach(e, x) for(__typeof(x.begin()) e = x.begin(); e != x.end(); ++e) #define SHOW_MEMORY(x) cout<<sizeof(x)/(1024*1024.)<<"MB"<<endl int n, l; char in[110]; int wid[110]; struct Trie { int next[1010][4], fail[1010], end[1010]; int L, root; 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 encode(char c) { switch(c) { case 'A': return 0; case 'C': return 1; case 'G': return 2; case 'T': return 3; } return -1; } void insert(char *s, int id) { int now = root; for(; *s; s++) { int w = encode(*s); if(next[now][w] == -1) next[now][w] = newnode(); now = next[now][w]; } end[now] |= (1 << id); } void build() { fail[root] = root; queue <int> Q; Q.push(root); 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] = now == root ? root : next[fail[now]][i]; else { fail[next[now][i]] = now == root ? root : next[fail[now]][i]; Q.push(next[now][i]); } } return; } int WID[1030]; void findWid() { for(int i = 0; i < (1 << n); i++) { WID[i] = 0; for(int j = 0; (1 << j) <= i; j++) { if(i & (1 << j)) WID[i] += wid[j]; } } return; } bool dp[2][1010][1030]; void solve() { //dp[i][j][k], 长度为i, 在j点, 包含关系为k的最大收益 findWid(); memset(dp, 0, sizeof(dp)); dp[0][0][0] = 1; int now = 0; for(int i = 1; i <= l; i++, now ^= 1) { memset(dp[now ^ 1], 0, sizeof(dp[now ^ 1])); for(int j = 0; j < L; j++) for(int k = 0; k < (1 << n); k++) if(dp[now][j][k]) for(int c = 0; c < 4; c++) dp[now ^ 1][next[j][c]][k | end[next[j][c]]] = 1; } int ans = -1; for(int j = 0; j < L; j++) for(int k = 0; k < (1 << n); k++) if(dp[now][j][k]) ans = max(ans, WID[k]); if(ans < 0) puts("No Rabbit after 2012!"); else printf("%d\n", ans); } }; Trie AC; int main() { while(scanf("%d %d", &n, &l) != EOF) { AC.init(); for(int i = 0; i < n; i++) scanf("%s %d", in, &wid[i]), AC.insert(in, i); AC.build(); AC.solve(); } return 0; }