【bzoj4212】神牛的養成計劃
阿新 • • 發佈:2018-11-10
Description
給你\(n\)個字串,接下來有\(m\)個詢問,每個詢問由兩個給定的字串\(s_1\)和\(s_2\)組成,對於每個詢問輸出\(n\)個字串中有多少個同時滿足\(s_1\)是其字首且\(s_2\)是其後綴,強制線上
資料範圍:\(n<=2000,m<=100000\),\(n\)個字串總長度以及詢問字串總長度均\(<=2000000\)
Solution
(怎麼感覺自己好像沒有學過trie一樣是因為太久沒有寫所以根本沒有往那個方向想嗎==)
最暴力的做法的話。。想法很簡單:先確定哪些字串滿足\(s_1\)
字首這種東西的話,如果說我們將\(n\)個字串丟到trie裡面,將dfs一遍之後各個字串結尾對應節點的訪問順序存在一個數組裡面,那麼對於一個詢問\((s_1,s_2)\),滿足\(s_1\)是字首的字串的結尾對應節點必定在一個子樹當中,反應到數組裡面的話就是一個區間
那所以接下來我們要做的就是查這個區間內的字串有多少個滿足\(s_2\)是字尾,只要將所有的串反轉然後丟到trie裡面,就又轉成查字首的問題了,解決方式和上面一樣
至於區間這個問題,直接可持久化一下就好了
mark:沒事還是不要隨便用getline好了==評測的時候超級容易翻車
mark:字首什麼的也是應該考慮一下trie啊qwq不要看到字串什麼的就滿腦子sa、sam之類的
程式碼大概長這個樣子
#include<iostream> #include<cstdio> #include<cstring> #include<vector> #define mp make_pair #define Pr pair<int,int> using namespace std; const int N=2010,L=2000010,C=26; string s[N],s1,s2; char tmps[L]; int st[N],lis[N]; int n,tot,lastans,m; namespace T1{/*{{{*/ const int N=::L; int ch[N][C],st[N],ed[N]; vector<int> mark[N]; int tot,rt; void init(){rt=1;tot=1;} void insert(string s,int id){ int len=s.length(),now=rt,c; for (int i=0;i<len;++i){ c=s[i]-'a'; if (!ch[now][c]) ch[now][c]=++tot; now=ch[now][c]; } mark[now].push_back(id); } void dfs(int x){ bool have=mark[x].size(); if (mark[x].size()){ st[x]=lis[0]+1; for (int i=0;i<mark[x].size();++i) lis[++lis[0]]=mark[x][i]; } bool flag=false; for (int i=0;i<C;++i){ if (!ch[x][i]) continue; dfs(ch[x][i]); if (!flag&&!have) st[x]=st[ch[x][i]]; flag=true; } ed[x]=lis[0]; } void get_order(){lis[0]=0; dfs(rt);} Pr query(string s){ int now=rt,len=s.length(),c; for (int i=0;i<len;++i){ //printf("%c\n",s[i]); c=(s[i]-'a'+lastans)%C; now=ch[now][c]; } if (!now) return mp(-1,-1); return mp(st[now],ed[now]); } }/*}}}*/ namespace T2{/*{{{*/ const int N=::L; int ch[N][C],rt[::N],cnt[N]; int tot; void init(){tot=0;rt[0]=0;} int newnode(int pre){ cnt[++tot]=cnt[pre]; for (int i=0;i<C;++i) ch[tot][i]=ch[pre][i]; return tot; } void _insert(int pre,int &x,string &s,int loc){ x=newnode(pre); ++cnt[x]; if (loc<0) return; int c=(s[loc]-'a'+lastans)%C; _insert(ch[pre][c],ch[x][c],s,loc-1); } void insert(int pre,int x,string &s){_insert(rt[pre],rt[x],s,s.length()-1);} int query(int l,int r,string s){ int nowl=rt[l],nowr=rt[r],c,len=s.length(); int ret=0; for (int i=len-1;i>=0&&(nowl||nowr);--i){ c=(s[i]-'a'+lastans)%C; nowl=ch[nowl][c]; nowr=ch[nowr][c]; } return cnt[nowr]-cnt[nowl]; } }/*}}}*/ void print(string s){ int len=s.length(); for (int i=0;i<len;++i) printf("%c",s[i]); printf("\n"); } void get_s(string &s){ scanf("%s",tmps); int len=strlen(tmps); s.resize(0); for (int i=0;i<len;++i) s.push_back(tmps[i]); } int main(){ #ifndef ONLINE_JUDGE freopen("a.in","r",stdin); #endif char ch; Pr rec; scanf("%d\n",&n); T1::init(); T2::init(); lastans=0; for (int i=1;i<=n;++i){ get_s(s[i]); //print(s[i]); T1::insert(s[i],i); } T1::get_order(); for (int i=1;i<=lis[0];++i){ T2::insert(i-1,i,s[lis[i]]); } scanf("%d\n",&m); for (int i=1;i<=m;++i){ get_s(s1); get_s(s2); //print(s1);print(s2); rec=T1::query(s1); if (rec.first!=-1) lastans=T2::query(rec.first-1,rec.second,s2); else lastans=0; printf("%d\n",lastans); } }