hihocoder #1465 : 后缀自动机五·重复旋律8
時間限制:10000ms
單點(diǎn)時限:1000ms
內(nèi)存限制:256MB
描述
小Hi平時的一大興趣愛好就是演奏鋼琴。我們知道一段音樂旋律可以被表示為一段數(shù)構(gòu)成的數(shù)列。
小Hi發(fā)現(xiàn)旋律可以循環(huán),每次把一段旋律里面最前面一個音換到最后面就成為了原旋律的“循環(huán)相似旋律”,還可以對“循環(huán)相似旋律”進(jìn)行相同的變換能繼續(xù)得到原串的“循環(huán)相似旋律”。
小Hi對此產(chǎn)生了濃厚的興趣,他有若干段旋律,和一部音樂作品。對于每一段旋律,他想知道有多少在音樂作品中的子串(重復(fù)便多次計(jì))和該旋律是“循環(huán)相似旋律”。
解題方法提示
輸入
第一行,一個由小寫字母構(gòu)成的字符串S,表示一部音樂作品。字符串S長度不超過100000。
第二行,一個整數(shù)N,表示有N段旋律。接下來N行,每行包含一個由小寫字母構(gòu)成的字符串str,表示一段旋律。所有旋律的長度和不超過 100000。
輸出
輸出共N行,每行一個整數(shù),表示答案。
樣例輸入
abac
3
a
ab
ca
樣例輸出
2
2
1?
?
思路: ?這個題目,由于要考慮循環(huán)相似,所以我們對所有的模式串進(jìn)行加倍處理,即添加相同的串到原串的最后。?
先對主串建立sam,然后模式串去主串上匹配,匹配的過程類似于spoj里面lcs和lcs2的做法,如果有這個字符的兒子,就沿著這個邊走下去,否則就跳轉(zhuǎn)到他的父親,直到某個點(diǎn)擁有當(dāng)前這個字符作為兒子,然后我們就走到這個兒子上去。 ?
每次統(tǒng)計(jì)當(dāng)前匹配的一個最大長度,如果這個最大長度超過或者等原來模式串的長度,那么我們就不斷向上沿著fa找到第一個a[i].len>=模式串長度,這樣保證模式串一定在這個節(jié)點(diǎn)所代表的集合里面出現(xiàn),然后答案累積上這個sz。
注意,由于會找到相同的節(jié)點(diǎn),而每個節(jié)點(diǎn)在一個模式串匹配中也只能被用1次,所以我們需要標(biāo)記已經(jīng)用過的節(jié)點(diǎn),用vis數(shù)組標(biāo)記。?
1 #include<bits/stdc++.h> 2 using namespace std; 3 int const N=100000+3; 4 struct node{ 5 int len,fa,ch[26]; 6 }a[N<<2]; 7 int n,tot,ls,sz[N<<1],num[N],sa[N<<1],vis[N<<1]; 8 vector<int> d; 9 char s[N]; 10 void add(int c,int id){ 11 int p=ls; 12 int np=ls=++tot; 13 a[np].len=a[p].len+1; 14 sz[np]=1; 15 for(;p&&!a[p].ch[c];p=a[p].fa) a[p].ch[c]=np; 16 if(!p) a[np].fa=1; 17 else { 18 int q=a[p].ch[c]; 19 if(a[q].len==a[p].len+1) a[np].fa=q; 20 else { 21 int nq=++tot;a[nq]=a[q]; 22 a[nq].len=a[p].len+1; 23 a[q].fa=a[np].fa=nq; 24 for(;p&& a[p].ch[c]==q;p=a[p].fa) 25 a[p].ch[c]=nq; 26 } 27 } 28 } 29 void solve(char *s){ 30 int len=strlen(s),ans=0,p=1,tmp=0; 31 d.clear(); 32 for(int i=0;i<2*len;i++) { 33 int c=s[i%len]-'a'; 34 if(a[p].ch[c]) tmp++,p=a[p].ch[c]; 35 else { 36 while (p && !a[p].ch[c]) p=a[p].fa; 37 if(!p) tmp=0,p=1; 38 else { 39 tmp=a[p].len+1; 40 p=a[p].ch[c]; 41 } 42 } 43 if(tmp>=len){ 44 int x=p,t=a[p].fa; 45 while (t && a[t].len>=len) 46 x=t,t=a[t].fa; 47 if(!vis[x]) ans+=sz[x],d.push_back(x); 48 vis[x]=1; 49 } 50 } 51 printf("%d\n",ans); 52 for(int i=0;i<d.size();i++) vis[d[i]]=0; 53 } 54 int main(){ 55 tot=ls=1; 56 scanf("%s",s); 57 int len=strlen(s); 58 for(int i=0;s[i];i++) 59 add(s[i]-'a',i+1); 60 for(int i=1;i<=tot;i++) num[a[i].len]++; 61 for(int i=1;i<=len;i++) num[i]+=num[i-1]; 62 for(int i=1;i<=tot;i++) sa[num[a[i].len]--]=i; 63 for(int i=tot;i>=1;i--){ 64 int x=sa[i]; 65 int f=a[x].fa; 66 sz[f]+=sz[x]; 67 } 68 scanf("%d",&n); 69 while (n--){ 70 scanf("%s",s); 71 solve(s); 72 } 73 return 0; 74 } View Code?
轉(zhuǎn)載于:https://www.cnblogs.com/ZJXXCN/p/11047149.html
總結(jié)
以上是生活随笔為你收集整理的hihocoder #1465 : 后缀自动机五·重复旋律8的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: springboot配置对jsp页面的解
- 下一篇: python作业6月14日