题目大意:
就是现在给出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;
}