[Luogu3538][POI2012]OKR-A Horrible Poem
2018-04-13 17:33
218 查看
luogu
如果字符串\(B\)是字符串\(A\)的循环节,那么\(A\)可以由\(B\)重复若干次得到。
\(|S|\le5*10^5,q\le2*10^6\)
1、\(|T|\)是\(|S|\)的约数。
2、\(S\)去掉\(T\)的前缀=\(S\)去掉\(T\)的后缀。
所以直接枚举某个\(|S|\)的约数然后判第二个条件。
复杂度\(O(q\sqrt n)\),直接跑了\(90\)分。
考虑优化。线性筛出每个数的最小质因数,然后先设答案为\(r-l+1\),每次考虑把答案的最小质因数除去并检验正确性。
复杂度可以降到\(O(q\log n)\)。
一份是先写的\(SA\)。判两个子串相等就是判两个后缀的\(lcp \ge len\)。
\(SA\)写完以后想想不对啊。我是来练\(hash\)的啊!于是又顺手写了一发\(hash\)。
题意
给出一个由小写英文字母组成的字符串\(S\),再给出\(q\)个询问,要求回答\(S\)某个子串的最短循环节。如果字符串\(B\)是字符串\(A\)的循环节,那么\(A\)可以由\(B\)重复若干次得到。
\(|S|\le5*10^5,q\le2*10^6\)
sol
考虑一个子串\(T\)要成为原串\(S\)的循环节的条件。1、\(|T|\)是\(|S|\)的约数。
2、\(S\)去掉\(T\)的前缀=\(S\)去掉\(T\)的后缀。
所以直接枚举某个\(|S|\)的约数然后判第二个条件。
复杂度\(O(q\sqrt n)\),直接跑了\(90\)分。
考虑优化。线性筛出每个数的最小质因数,然后先设答案为\(r-l+1\),每次考虑把答案的最小质因数除去并检验正确性。
复杂度可以降到\(O(q\log n)\)。
code
有两份代码。一份是先写的\(SA\)。判两个子串相等就是判两个后缀的\(lcp \ge len\)。
#include<cstdio> #include<algorithm> #include<cmath> using namespace std; int gi() { int x=0,w=1;char ch=getchar(); while ((ch<'0'||ch>'9')&&ch!='-') ch=getchar(); if (ch=='-') w=0,ch=getchar(); while (ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar(); return w?x:-x; } const int N = 5e5+5; int n,q,t ,x ,y ,SA ,Rank ,Height[22] ,lg ,pri ,tot,zhi ,p ; char s ; bool cmp(int i,int j,int k){return y[i]==y[j]&&y[i+k]==y[j+k];} void getSA() { int m=30; for (int i=1;i<=n;++i) ++t[x[i]=s[i]-'a'+1]; for (int i=1;i<=m;++i) t[i]+=t[i-1]; for (int i=n;i>=1;--i) SA[t[x[i]]--]=i; for (int k=1;k<=n;k<<=1) { int p=0; for (int i=0;i<=m;++i) y[i]=0; for (int i=n-k+1;i<=n;++i) y[++p]=i; for (int i=1;i<=n;++i) if (SA[i]>k) y[++p]=SA[i]-k; for (int i=0;i<=m;++i) t[i]=0; for (int i=1;i<=n;++i) ++t[x[y[i]]]; for (int i=1;i<=m;++i) t[i]+=t[i-1]; for (int i=n;i>=1;--i) SA[t[x[y[i]]]--]=y[i]; swap(x,y); x[SA[1]]=p=1; for (int i=2;i<=n;++i) x[SA[i]]=cmp(SA[i],SA[i-1],k)?p:++p; if (p>=n) break;m=p; } for (int i=1;i<=n;++i) Rank[SA[i]]=i; for (int i=1,j=0;i<=n;++i) { if (j) --j; while (s[i+j]==s[SA[Rank[i]-1]+j]) ++j; Height[0][Rank[i]]=j; } for (int j=1;j<22;++j) for (int i=1;i+(1<<j-1)<=n;++i) Height[j][i]=min(Height[j-1][i],Height[j-1][i+(1<<j-1)]); for (int i=2;i<=n;++i) lg[i]=lg[i>>1]+1; } int lcp(int i,int j) { i=Rank[i];j=Rank[j];if (i>j) swap(i,j); if (i==j) return (int)1e9; ++i;int k=lg[j-i+1]; return min(Height[k][i],Height[k][j-(1<<k)+1]); } bool check(int l,int r,int sz) { return lcp(l,l+sz)>=r-l+1-sz; } int main() { n=gi();scanf("%s",s+1);getSA();q=gi(); for (int i=2;i<=n;++i) { if (!zhi[i]) pri[++tot]=i,p[i]=i; for (int j=1;j<=tot&&i*pri[j]<=n;++j) { zhi[i*pri[j]]=1;p[i*pri[j]]=pri[j]; if (i%pri[j]==0) break; } } while (q--) { int l=gi(),r=gi(),ans=r-l+1; for (int i=r-l+1;i>1;i/=p[i]) if (check(l,r,ans/p[i])) ans/=p[i]; printf("%d\n",ans); } return 0; }
\(SA\)写完以后想想不对啊。我是来练\(hash\)的啊!于是又顺手写了一发\(hash\)。
#include<cstdio> #include<algorithm> #include<cmath> using namespace std; #define ull unsigned long long int gi() { int x=0,w=1;char ch=getchar(); while ((ch<'0'||ch>'9')&&ch!='-') ch=getchar(); if (ch=='-') w=0,ch=getchar(); while (ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar(); return w?x:-x; } const int N = 5e5+5; const int base = 233; int n,q,pri ,tot,zhi ,p ; char s ;ull pw ,hash ; ull cal(int l,int r){return hash[r]-hash[l-1]*pw[r-l+1];} bool check(int l,int r,int sz){return cal(l,r-sz)==cal(l+sz,r);} int main() { pw[0]=1; for (int i=1;i<N;++i) pw[i]=pw[i-1]*base; n=gi();scanf("%s",s+1);q=gi(); for (int i=1;i<=n;++i) hash[i]=hash[i-1]*base+s[i]; for (int i=2;i<=n;++i) { if (!zhi[i]) pri[++tot]=i,p[i]=i; for (int j=1;j<=tot&&i*pri[j]<=n;++j) { zhi[i*pri[j]]=1;p[i*pri[j]]=pri[j]; if (i%pri[j]==0) break; } } while (q--) { int l=gi(),r=gi(),ans=r-l+1; for (int i=r-l+1;i>1;i/=p[i]) if (check(l,r,ans/p[i])) ans/=p[i]; printf("%d\n",ans); } return 0; }
相关文章推荐
- BZOJ2795 [Poi2012]A Horrible Poem
- bzoj 2795: [Poi2012]A Horrible Poem (hash+数论)
- [POI 2012]A Horrible Poem(字符串Hash)
- BZOJ2795: [Poi2012]A Horrible Poem
- 2795: [Poi2012]A Horrible Poem
- 【bzoj2795】[Poi2012]A Horrible Poem hash
- bzoj2795: [Poi2012]A Horrible Poem
- [Poi2012]A Horrible Poem BZOJ2795
- 2795: [Poi2012]A Horrible Poem hash
- 【POI2012】【BZOJ2795】A Horrible Poem
- [BZOJ2795] [Poi2012] [字符串hash] A Horrible Poem
- 2795: [Poi2012]A Horrible Poem
- [BZOJ 2795]POI2012 A Horrible Poem
- [POI2012]A Horrible Poem
- BZOJ2795/POI2012 A horrible poem
- bzoj2795[Poi2012]A Horrible Poem 暴力hash
- [BZOJ2795][Poi2012]A Horrible Poem
- BZOJ 2795 Poi2012 A Horrible Poem Hash
- bzoj 2795: [Poi2012]A Horrible Poem hash
- BZOJ2795: [Poi2012]A Horrible Poem