[bzoj4084][Sdoi2015]双旋转字符串_hash
雙旋轉字符串 bzoj-4084 Sdoi-2015
題目大意:給定兩個字符串集合 S 和 T 。其中 S 中的所有字符串長度都恰好為 N ,而 T 中所有字符串長度都恰好為 M 。且 N+M 恰好為偶數。如果記 S 中字符串全體為 S1,S2,...,STotalS ,而 T 中字符串全體為 T1,T2,...,TTotalT 。現在希望知道有多少對 <i,j> ,滿足將 Si 和 Tj 拼接后得到的字符串 Si+Tj 滿足雙旋轉性。一個長度為偶數字符串 W 可以表示成兩段長度相同的字符串的拼接,即W=U+V。如果 V 可以通過 U 旋轉得到,則稱 W 是滿足雙旋轉性的。比如說字符串 U=“vijos”可以通過旋轉得到“ijosv”,“josvi”,“osvij” 或“svijo”。那么“vijosjosvi”就是滿足雙旋轉性的字符串。
想法:我們將小的集合所有串hash然后存起來,這一步是容易的。對于大串我們將他所有旋轉后的前(len1-mid)也存起來,這里只需要將每一個大串在尾部copy一遍,然后hash前綴和即可。mid的意思就是大、小串的長度平均值。然后暴力枚舉匹配即可。
最后,附上丑陋的代碼... ...
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <map> #define N 8000010 using namespace std; typedef unsigned long long ull; ull h[N],g[N],f[N]; map<ull,int>MP; char s[N]; int ans; const int base=233; int n,m,S,T,k,mid; void find() {ull x=0;int cnt=0;for(int i=mid+1;i<=n;i++) x=x*base+s[i];for(int i=1;i<=mid;i++) s[i+mid]=s[i];for(int i=1;i<=mid*2;i++) f[i]=f[i-1]*base+s[i];for(int i=1;i<=mid;i++){ull y=f[i+k-1]-f[i-1]*h[k];if(y!=x) continue;g[++cnt]=f[i+mid-1]-f[i+k-1]*h[mid-k];}sort(g+1,g+cnt+1);for(int i=1;i<=cnt;i++) if(g[i]!=g[i-1]) MP[g[i]]++; } int main() {scanf("%d%d%d%d",&S,&T,&n,&m);h[0]=1;for(int i=1;i<=n+m;i++) h[i]=h[i-1]*base;mid=(n+m)>>1;k=n-mid;for(int i=1;i<=S;i++){scanf("%s",s+1);find();}for(int i=1;i<=T;i++){scanf("%s",s+1);ull x=0;for(int j=1;j<=m;j++) x=x*base+s[j];ans+=MP[x];}printf("%d",ans); }?
小結:map真好用...hash真強... ...
轉載于:https://www.cnblogs.com/ShuraK/p/9333133.html
總結
以上是生活随笔為你收集整理的[bzoj4084][Sdoi2015]双旋转字符串_hash的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 数据结构-链表:对链表进行初始化、增删改
- 下一篇: otg android 键盘,使用USB