牛客-白兔的字串(Hash+二分)
阿新 • • 發佈:2020-07-24
題目連結:https://ac.nowcoder.com/acm/problem/15253
題目描述
白兔有一個字串T。白雲有若干個字串S1,S2..Sn。
白兔想知道,對於白雲的每一個字串,它有多少個子串是和T迴圈同構的。
提示:對於一個字串a,每次把a的第一個字元移動到最後一個,如果操作若干次後能夠得到字串b,則a和b迴圈同構。
所有字元都是小寫英文字母
輸入描述:
第一行一個字串T(|T|<=10^6)
第二行一個正整數n (n<=1000)
接下來n行為S1~Sn (|S1|+|S2|+…+|Sn|<=10^7),max(|S1|,|S2|,|S3|,|S4|,..|Sn|)<=10^6
輸出描述:
輸出n行表示每個串的答案
輸入
abab
2
abababab
ababcbaba
輸出
5
2
既然是迴圈同構,那麼我們可以將串T展開成2|T|的長度,然後用Hash儲存每種T長度下的值,接下來我們在遍歷以下n個字串的時候可以直接查詢上面是否出現了字串,如果有的話那麼ans++,至於查詢的方式,用map的話比較慢,會T掉,用二分就可以了(我們先排好序),實際上極限的理論複雜度是\(O(log|T|\sum S)\),也會T掉的。。。只不過很少有程式碼會跑到這種極限複雜度的。
以下是AC程式碼:
#include <bits/stdc++.h> using namespace std; typedef unsigned long long ull; const int mac=2e6+10; char ss[mac],s[mac]; ull hashs[mac],wei[mac]; int base=131; int main() { scanf ("%s",ss); int len=strlen(ss); for (int i=0; i<len; i++) ss[len+i]=ss[i]; ull hash=0,cnt=0; wei[0]=1; for (int i=1; i<mac; i++) wei[i]=wei[i-1]*base; int num=0; for (int i=0; i<len*2-1; i++){ hash=hash*base+ss[i]; cnt++; if (cnt==len){ cnt--; hashs[++num]=hash; hash=hash-wei[len-1]*ss[i-len+1]; } } sort(hashs+1,hashs+num+1); int n; scanf ("%d",&n); for (int i=1; i<=n; i++){ scanf ("%s",s); int lens=strlen(s); int ans=0; hash=0,cnt=0; for (int i=0; i<lens; i++){ hash=hash*base+s[i]; cnt++; if (cnt==len){ cnt--; int pos=lower_bound(hashs+1,hashs+num+1,hash)-hashs-1; if (pos<num && hashs[pos+1]==hash) ans++; hash=hash-wei[len-1]*s[i-len+1]; } } printf("%d\n",ans); } return 0; }