【LOJ】#2278. 「HAOI2017」字串
阿新 • • 發佈:2018-12-01
題解
好神仙的題啊
感覺轉二維平面能想到,算重複情況的方法真想不到啊
通過扒stdcall程式碼獲得的題解QAQQQQ
我們先把\(p_i\)正串反串建出一個AC自動機來
然後我們把s串放在上面跑匹配,正著跑一遍,反著跑一遍,我們就得到了\(s\)中每個位置正著和反著能匹配到的節點編號
然後對於AC自動機,我們建出fail樹來,並處理出每個點在fail樹上dfs序
對於AC自動機上的一個點,我們把\(p_i\)正串的詢問掛在上面,假如這個點的匹配深度為x,那麼我們就需要對於這個點fail樹裡所有匹配到的\(s\)中正著匹配到的位置,問這個位置a,\(a + k + 1\)是不是在\(p_i\)
舉個例子
k = 3
假如\(p_i\)是
abacdefg
然後s中的一段是
abahdefg
我們找到\(p_i\)在AC自動機中aba所在的節點,掛上\(p_i\)這個詢問,找出所有這個節點fail樹裡匹配到的s正串的位置\(a\)
查詢的是\(p_i\)反串gfe所在節點fail樹子樹裡,問\(a + k + 1\)有多少個
這個可以通過樹狀陣列維護,問一個點子樹裡的只要用遍歷子樹後的值減掉遍歷子樹前的值就好
然而……你發現這樣統計會有重複了嗎
還是剛剛那個例子
我們發現,當我們在a所在的節點時,我們還會計算一遍這一段
為了去重,我們使得左邊匹配要到達最長,也就是,如果這個位置\(a + k\)也合法的話,那麼我們要減掉它
就是在aba這個點,同時掛上gfed節點,然後減掉這些方案
維護方法還是樹狀陣列,和上面類似
程式碼
#include <bits/stdc++.h> #define fi first #define se second #define pii pair<int,int> #define pdi pair<db,int> #define mp make_pair #define pb push_back #define enter putchar('\n') #define space putchar(' ') #define eps 1e-8 #define MAXN 200005 #define mo 974711 //#define ivorysi using namespace std; typedef long long int64; typedef double db; template<class T> void read(T &res) { res = 0;char c = getchar();T f = 1; while(c < '0' || c > '9') { if(c == '-') f = -1; c = getchar(); } while(c >= '0' && c <= '9') { res = res * 10 + c - '0'; c = getchar(); } res *= f; } template<class T> void out(T x) { if(x < 0) {x = -x;putchar('-');} if(x >= 10) { out(x / 10); } putchar('0' + x % 10); } int L[MAXN],R[MAXN],K,N,dfn[MAXN * 2],idx,siz[MAXN * 2],H,ans[MAXN],pos[2][MAXN]; char s[MAXN],t[MAXN]; vector<int> son[MAXN * 2]; vector<int> ver[MAXN * 2]; vector<pii > Qry[MAXN * 2]; int sum[2][MAXN * 2]; namespace ACAM { int tr[MAXN * 2][94],fail[MAXN * 2],Ncnt,rt,que[MAXN * 2],ql,qr; void Init() { Ncnt = 1,rt = 1; } int ins(int p,int c) { if(!tr[p][c]) tr[p][c] = ++Ncnt; return tr[p][c]; } void build_ACAM() { ql = 1,qr = 0; que[++qr] = 1;fail[1] = 1; while(ql <= qr) { int u = que[ql++]; for(int i = 0 ; i <= 93 ; ++i) { if(tr[u][i]) { int v = tr[u][i]; int t = fail[u]; if(u == 1) fail[v] = 1; else { while(1) { if(tr[t][i]) {fail[v] = tr[t][i];break;} if(t == 1) {fail[v] = 1;break;} t = fail[t]; } } que[++qr] = v; son[fail[v]].pb(v); } } } } } using ACAM::ins; void dfs(int u) { dfn[u] = ++idx;siz[u] = 1; int s = son[u].size(); for(int i = 0 ; i < s ; ++i) { dfs(son[u][i]); siz[u] += siz[son[u][i]]; } } int lowbit(int x) {return x & (-x);} void insert(int on,int x) { while(x <= ACAM::Ncnt) { sum[on][x]++; x += lowbit(x); } } int Query(int on,int x) { int res = 0; while(x > 0) { res += sum[on][x]; x -= lowbit(x); } return res; } int Query_Range(int on,int x) { return Query(on,dfn[x] + siz[x] - 1) - Query(on,dfn[x] - 1); } void Process(int u) { int s = Qry[u].size(); for(int i = 0 ; i < s ; ++i) { if(Qry[u][i].se > 0) ans[Qry[u][i].fi] -= Query_Range(0,Qry[u][i].se); if(Qry[u][i].se < 0) ans[Qry[u][i].fi] += Query_Range(1,-Qry[u][i].se); } s = ver[u].size(); for(int i = 0 ; i < s ; ++i) { if(ver[u][i] > 0) insert(0,dfn[ver[u][i]]); if(ver[u][i] < 0) insert(1,dfn[-ver[u][i]]); } s = son[u].size(); for(int i = 0 ; i < s ; ++i) { Process(son[u][i]); } s = Qry[u].size(); for(int i = 0 ; i < s ; ++i) { if(Qry[u][i].se > 0) ans[Qry[u][i].fi] += Query_Range(0,Qry[u][i].se); if(Qry[u][i].se < 0) ans[Qry[u][i].fi] -= Query_Range(1,-Qry[u][i].se); } } void Solve() { read(K); scanf("%s",s + 1); H = strlen(s + 1); read(N); ACAM::Init(); for(int i = 1 ; i <= N ; ++i) { scanf("%s",t + 1); int len = strlen(t + 1); int p = 1; if(len > K) { for(int j = 1 ; j <= len ; ++j) { p = ins(p,t[j] - 33); L[j] = p; } p = 1; for(int j = len ; j >= 1 ; --j) { p = ins(p,t[j] - 33); R[j] = p; } for(int j = 0 ; j <= len - K; ++j) { int a = j == 0 ? 1 : L[j]; int b = j + K + 1 == len + 1 ? 1 : R[j + K + 1]; Qry[a].pb(mp(i,b)); } for(int j = 1 ; j <= len - K; ++j) { int a = L[j],b = R[j + K]; Qry[a].pb(mp(i,-b)); } } else ans[i] = H - len + 1; } ACAM::build_ACAM(); int p = 1; pos[0][0] = 1; for(int i = 1 ; i <= H ; ++i) { while(1) { if(ACAM::tr[p][s[i] - 33]) {p = ACAM::tr[p][s[i] - 33];break;} else if(p == 1) break; p = ACAM::fail[p]; } pos[0][i] = p; } p = 1; pos[1][H + 1] = 1; for(int i = H ; i >= 1 ; --i) { while(1) { if(ACAM::tr[p][s[i] - 33]) {p = ACAM::tr[p][s[i] - 33];break;} else if(p == 1) break; p = ACAM::fail[p]; } pos[1][i] = p; } dfs(1); for(int i = 0 ; i <= H - K; ++i) { ver[pos[0][i]].pb(pos[1][i + K + 1]); } for(int i = 1 ; i <= H - K; ++i) { ver[pos[0][i]].pb(-pos[1][i + K]); } Process(1); for(int i = 1 ; i <= N ; ++i) { out(ans[i]);enter; } } int main() { #ifdef ivorysi freopen("f1.in","r",stdin); #endif Solve(); }