Anthem of Berland AC自動機或KMP DP
阿新 • • 發佈:2018-12-11
題意:
給你一個帶?的字串S,和一個字串T,問把?替換後最多能匹配多少次T?可以重疊匹配。
題解:
這種肯定是要DP的。
怎麼DP呢?
AC自動機上的DP問題很多,這個也可以用AC自動機。
dp[i][j]表示當前在S串的i位置,在AC自動機的j狀態時能完整匹配T的次數。
當i是問號時列舉26個字母轉移,不是問號直接轉移到這個字元。
滾動陣列一下即可。
當然KMP也是可以的,因為只有一個串。不過需要手動建一下next陣列,跟AC自動機一樣。
程式碼:
#include <cstdio> #include <iostream> #include <algorithm> #include <cstring> #include <queue> #include <bitset> #include <map> #include <vector> #include <stack> #include <set> #include <unordered_map> #include <unordered_set> #include <cmath> #include <ctime> #ifdef LOCAL #define debug(x) cout<<#x<<" = "<<(x)<<endl; #else #define debug(x) 1; #endif #define chmax(x,y) x=max(x,y) #define chmin(x,y) x=min(x,y) #define lson id<<1,l,mid #define rson id<<1|1,mid+1,r #define lowbit(x) x&-x #define mp make_pair #define pb push_back #define fir first #define sec second using namespace std; typedef long long ll; typedef unsigned long long ull; typedef pair<ll, int> pii; const int MOD = 1e9 + 7; const double PI = acos (-1.); const double eps = 1e-10; const int INF = 0x3f3f3f3f; const ll INFLL = 0x3f3f3f3f3f3f3f3f; const int MAXN = 2e5 + 5; char s[MAXN], t[MAXN]; const int SIGMA_SIZE = 130; const int MAXNODE = 2e5 + 100; const int MAXS = 150 + 10; struct ACautomata { int ch[MAXNODE][SIGMA_SIZE]; int f[MAXNODE]; // fail函式 int val[MAXNODE]; // 每個字串的結尾結點都有一個非0的val int last[MAXNODE]; // 輸出連結串列的下一個結點 //int cnt[MAXS]; int sz; void init() { sz = 1; memset(ch[0], 0, sizeof(ch[0])); // memset(cnt, 0, sizeof(cnt)); } // 字元c的編號 inline int idx(char c) { return c - 'a'; } // 插入字串。v必須非0 void insert(char *s, int v) { int u = 0, n = strlen(s); for(int i = 0; i < n; i++) { int c = idx(s[i]); if(!ch[u][c]) { memset(ch[sz], 0, sizeof(ch[sz])); val[sz] = 0; ch[u][c] = sz++; } u = ch[u][c]; } val[u] = v; } // 計算fail函式 void getFail() { queue<int> q; f[0] = 0; // 初始化佇列 for(int c = 0; c < SIGMA_SIZE; c++) { int u = ch[0][c]; if(u) { f[u] = 0; q.push(u); last[u] = 0; } } // 按BFS順序計算fail while(!q.empty()) { int r = q.front(); q.pop(); for(int c = 0; c < SIGMA_SIZE; c++) { int u = ch[r][c]; if(!u) { ch[r][c]=ch[f[r]][c]; continue; } q.push(u); int v = f[r]; while(v && !ch[v][c]) v = f[v]; f[u] = ch[v][c]; last[u] = val[f[u]] ? f[u] : last[f[u]]; } } } } ac; int d[2][MAXN]; int main() { #ifdef LOCAL freopen ("input.txt", "r", stdin); #endif scanf("%s %s", s + 1, t + 1); ac.init(); ac.insert(t + 1, 1); ac.getFail(); int n = strlen(s + 1), m = strlen(t + 1); memset(d, -1, sizeof(d)); d[0][0] = 0; for (int i = 1; i <= n; i++) { for (int j = 0; j <= m; j++) d[i & 1][j] = -1; for (int j = 0; j <= m; j++) { if(d[i & 1 ^ 1][j] == -1) continue; if (s[i] == '?') { for (int k = 0; k < 26; k++) d[i & 1][ac.ch[j][k]] = max(d[i & 1 ^ 1][j] + (ac.ch[j][k] == m) , d[i & 1][ac.ch[j][k]]); } else d[i & 1][ac.ch[j][s[i] - 'a']] = max(d[i & 1 ^ 1][j] + (ac.ch[j][s[i] - 'a'] == m) , d[i & 1][ac.ch[j][s[i] - 'a']]); } } int ans = 0; for (int i = 0; i <= m; i++) ans = max(ans, d[n & 1][i]); printf("%d\n", ans); return 0; }