跟 HDU 4057 Rescue the Rabbit差不多的AC自动机+dp,比赛的时候被虐成傻逼了!!!
999的状态不多,直接状态压缩就行。dp[i][ACstatus][status] 到字符串第i位置,在AC自动机上状态为ACstatus,包含到999的状态为status。
更新了一下自动机的模板。。。Orz简洁写法
View Code
#include <iostream> #include <cstdio> #include <cmath> #include <vector> #include <cstring> #include <algorithm> #include <string> #include <set> #include <functional> #include <numeric> #include <sstream> #include <stack> #include <map> #include <queue> #define CL(arr, val) memset(arr, val, sizeof(arr)) #define REP(i, n) for((i) = 0; (i) < (n); ++(i)) #define FOR(i, l, h) for((i) = (l); (i) <= (h); ++(i)) #define FORD(i, h, l) for((i) = (h); (i) >= (l); --(i)) #define L(x) (x) << 1 #define R(x) (x) << 1 | 1 #define MID(l, r) (l + r) >> 1 #define Min(x, y) (x) < (y) ? (x) : (y) #define Max(x, y) (x) < (y) ? (y) : (x) #define E(x) (1 << (x)) #define iabs(x) (x) < 0 ? -(x) : (x) #define OUT(x) printf("%lld\n", x) #define Read() freopen("data.in", "r", stdin) #define Write() freopen("data.out", "w", stdout); typedef long long LL; const double eps = 1e-6; const double PI = acos(-1.0); const int inf = 0x1F1F1F1F; using namespace std; const int N = 1610; struct node { int val; short type; bool cannot; short index; node *pre, *next[26]; void init() { val = type = 0; index = cannot = 0; pre = NULL; memset(next, 0, sizeof(next)); } }; node trie[N]; node *root, *q[N]; int cnt, must; int dp[2][N][1<<8]; int vv[2][N][1<<8]; char str[110]; void insert(node* root, char* str, int val) { int c, i; for(i = 0; str[i] != 0; ++i) { c = str[i] - 'a'; if(root->next[c] == 0) { root->next[c] = &trie[++cnt]; root->next[c]->init(); root->next[c]->index = cnt; } root = root->next[c]; } if(val == 999) { root->type |= (1<<must++); } else if(val == -999) { root->cannot = 1; } else { root->val += val; } } void buildAC() { int head, tail, i; node *u; root->pre = root; head = tail = 0; q[tail++] = root; while(head < tail) { u = q[head++]; u->val += u->pre->val; u->type |= u->pre->type; u->cannot |= u->pre->cannot; for(i = 0; i < 26; ++i) { if(u->next[i] == 0) { if(u == root) u->next[i] = root; else u->next[i] = u->pre->next[i]; } else { if(u == root) u->next[i]->pre = root; else u->next[i]->pre = u->pre->next[i]; /* if(u->next[i]->pre->val) u->next[i]->val += u->next[i]->pre->val; if(u->next[i]->pre->type) u->next[i]->type |= u->next[i]->pre->type; if(u->next[i]->pre->cannot) u->next[i]->cannot = 1; */ q[tail++] = u->next[i]; } } } } void solve() { int i, j, k, c; int nxt, val, tt, n = strlen(str); CL(dp[1], 0x1f); CL(vv[1], 0); dp[1][0][0] = 0; vv[1][0][0] = 0; for(i = 0; i < n; ++i) { CL(dp[i&1], 0x1f); CL(vv[i&1], 0); for(j = 0; j <= cnt; ++j) { for(k = 0; k < (1<<must); ++k) { if(dp[(i+1)&1][j][k] >= inf) continue; if(dp[i&1][j][k] > dp[(i+1)&1][j][k] + 1) { dp[i&1][j][k] = dp[(i+1)&1][j][k] + 1; vv[i&1][j][k] = vv[(i+1)&1][j][k]; } else if(dp[i&1][j][k] == dp[(i+1)&1][j][k] + 1 && vv[i&1][j][k] < vv[(i+1)&1][j][k]) { vv[i&1][j][k] = vv[(i+1)&1][j][k]; } c = str[i] - 'a'; nxt = trie[j].next[c]->index; if(trie[nxt].cannot) continue; val = trie[nxt].val; tt = k|trie[nxt].type; if(dp[i&1][nxt][tt] > dp[(i+1)&1][j][k]) { dp[i&1][nxt][tt] = dp[(i+1)&1][j][k]; vv[i&1][nxt][tt] = vv[(i+1)&1][j][k] + val; } else if( dp[i&1][nxt][tt] == dp[(i+1)&1][j][k] && vv[i&1][nxt][tt] < vv[(i+1)&1][j][k] + val) { vv[i&1][nxt][tt] = vv[(i+1)&1][j][k] + val; } } } } int ans1 = inf, ans2 = 0, full = (1<<must) - 1; for(j = 0; j <= cnt; ++j) { if(ans1 > dp[(n-1)&1][j][full]) { ans1 = dp[(n-1)&1][j][full]; ans2 = vv[(n-1)&1][j][full]; } if(ans1 == dp[(n-1)&1][j][full] && ans2 < vv[(n-1)&1][j][full]) { ans2 = vv[(n-1)&1][j][full]; } } if(ans1 == inf) puts("Banned"); else printf("%d %d\n", ans1, ans2); } int main() { //freopen("data.in", "r", stdin); int T, n, g, cas = 0; scanf("%d", &T); while(T--) { root = &trie[0]; root->init(); cnt = must = 0; scanf("%d", &n); while(n--) { scanf("%s %d", str, &g); insert(root, str, g); } buildAC(); scanf("%s", str); printf("Case %d: ", ++cas); solve(); } return 0; }