玄武密碼(bzoj4327)(JSOI2012)
阿新 • • 發佈:2018-10-07
關系 gets 圖案 for etc pan 難題 自然 %d
題目描述和題其實莫得關系
題目描述
原題來自:JSOI 2012
在美麗的玄武湖畔,雞鳴寺邊,雞籠山前,有一塊富饒而秀美的土地,人們喚作進香河。相傳一日,一縷紫氣從天而至,只一瞬間便消失在了進香河中。老人們說,這是玄武神靈將天書藏匿在此。
很多年後,人們終於在進香河地區發現了帶有玄武密碼的文字。更加神奇的是,這份帶有玄武密碼的文字,與玄武湖南岸臺城的結構有微妙的關聯。於是,漫長的破譯工作開始了。
經過分析,我們可以用東南西北四個方向來描述臺城城磚的擺放,不妨用一個長度為 NNN 的序列來描述,序列中的元素分別是 E
,S
,W
,N
,代表了東南西北四向,我們稱之為母串。而神秘的玄武密碼是由四象的圖案描述而成的 MMM 段文字。這裏的四象,分別是東之青龍,西之白虎,南之朱雀,北之玄武,對東南西北四向相對應。
現在,考古工作者遇到了一個難題。對於每一段文字,其前綴在母串上的最大匹配長度是多少呢?
輸入格式
第一行有兩個整數,NNN 和 MMM,分別表示母串的長度和文字段的個數;
第二行是一個長度為 NNN 的字符串,所有字符都滿足是 E
,S
,W
和 N
中的一個;
之後 MMM 行,每行有一個字符串,描述了一段帶有玄武密碼的文字。依然滿足,所有字符都滿足是 E
,S
,W
和 N
中的一個。
輸出格式
輸出有 MMM 行,對應 MMM 段文字。
每一行輸出一個數,表示這一段文字的前綴與母串的最大匹配串長度。
樣例
樣例輸入
7 3
SNNSSNS
NNSS
NNN
WSEE
樣例輸出
4
2
0
數據範圍與提示
對於全部數據,1≤N≤10^7,1≤M≤10^5,保證每一段文字的長度均小於等於 100。
題目描述和題其實莫得關系
上來很自然的想到了KMP 然後發現O(n*100m)會T 然後發現了AC自動機的正解,很SB的寫了一上午(最主要的是教練一直說這次初賽分數線提高了,慌得一批) 首先我們建樹,然後把主串放在上面跑,很顯然,對於每一個前綴如果能夠成功匹配,那麽它的nxt肯定也可以 對於每一個可以匹配的地方,我們標記一次,最後對於每一個模式串都從後往前跑一遍,當我們發現一個地方被標記後,就輸出答案(從後往前跑所找到的第一個一定是最長的能匹配的前綴) 還有就是這道題的數據範圍很迷,數組一定要開夠 下面給出代碼:
#include<iostream> #include<algorithm> #include<cstdio> #include<cstdlib> #include<cstring> #include<string> #include<cmath> using namespace std; inline int rd(){ int x=0,f=1; char ch=getchar(); for(;!isdigit(ch);ch=getchar()) if(ch==‘-‘) f=-1; for(;isdigit(ch);ch=getchar()) x=x*10+ch-‘0‘; return x*f; } inline void write(int x){ if(x<0) putchar(‘-‘),x=-x; if(x>9) write(x/10); putchar(x%10+‘0‘); return ; } int n,m; char s[10000006],a[106]; int trie[1000006][4]; int len[100006],f[10000006]; int vis[10000006]; int tot=1; int calc(char ch){ if(ch==‘E‘) return 0; if(ch==‘W‘) return 1; if(ch==‘N‘) return 2; if(ch==‘S‘) return 3; } void pre(int x){ int c=1; for(int i=1;i<=len[x];i++){ int h=calc(a[i]); if(!trie[c][h]){ f[++tot]=c; trie[c][h]=tot; } c=trie[c][h]; } vis[x]=c; return ; } int q[1000006]; int l=0,r=0; int nxt[1000006]; void get_next(){ q[++r]=1; for(int i=0;i<=3;i++) trie[0][i]=1; nxt[1]=0; while(l<r){ int h=q[++l]; for(int i=0;i<=3;i++){ if(!trie[h][i]) trie[h][i]=trie[nxt[h]][i]; else{ nxt[trie[h][i]]=trie[nxt[h]][i]; q[++r]=trie[h][i]; } } } return ; } bool book[1000006]; void solve(){ int c=1; for(int i=1;i<=n;i++){ int h=calc(s[i]); c=trie[c][h]; for(int j=c;j;j=nxt[j]){ if(book[j]) break; book[j]=1; } } return ; } int gets(int x){ int ans=len[x]; for(int i=vis[x];i;i=f[i],ans--) if(book[i]) return ans; } int main(){ n=rd(),m=rd(); scanf("%s",s+1); for(int i=1;i<=m;i++){ scanf("%s",a+1); len[i]=strlen(a+1); pre(i); } get_next(); solve(); for(int i=1;i<=m;i++) printf("%d\n",gets(i)); return 0; }
玄武密碼(bzoj4327)(JSOI2012)