【题解】【P3538 [POI2012]OKR-A Horrible Poem】

【题解】【P3538 [POI2012]OKR-A Horrible Poem】

Analysis

  1. 首先循环节和border一一对应,所以判断某个长度x是否为循环节,可以直接判断len-x是否是border,判断方法有两种,hash或者后缀数组都可以。
  2. 因此有一种做法:从小到大枚举询问子串长度的所有约数,并利用上述判断方法O(1)判断,约数可以预处理出来。总复杂度O(q),但是有个点会T
  3. 上述方法复杂度近似O(qn),考虑优化。先提出一个引理:字符串的所有循环节都是最小循环节的倍数。(证明见Tip)。那么len一定是最小循环节的倍数,然后枚举len的所有质因子,若len/p可以作为循环节,那么len/p一定是最小循环节的倍数,令len/=p。将len的质因子枚举完后,最后的len显然就是答案。一个数质因子的个数是log级别的,可以通过本题。可以通过筛法预先筛出每个数的质因子集合。
    Tip:我们可以将字符串的循环节类比成周期函数,设存在两个循环节x,y,则f(i)=f(i+x)=f(i+y),那么f(i)=f(i+y-x),进一步f(i)=f(i+y%x)。可以发现这个过程与辗转相除法类似。最终可以推出gcd(x,y)是循环节,因此,若存在一个循环节不是最小循环节的倍数,那么一定存在一个比最小循环节还要小的循环节,就会出现矛盾。

Code

#include<bits/stdc++.h>
using namespace std;
//#define int long long
inline int read()
{
register int x=0,w=1;
register char ch=getchar();
while((ch<'0'||ch>'9')&&ch!='-') ch=getchar();
if(ch=='-') {ch=getchar();w=-1;}
while(ch>='0'&&ch<='9') {x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
return x*w;
}
inline void write(int x)
{
if(x<0) putchar('-'),x=~(x-1);
if(x>9) write(x/10);
putchar('0'+x%10);
}
const int N=5e5+100;
char s[N];
int rk[N],y[N<<1],t[N],n,m=128,q,sa[N],h[N],st[N][20],mxlg[N];
vector<int>d[N];
void getsa()
{
for(int i=1;i<=n;++i) t[rk[i]=s[i]]++;
for(int i=1;i<=m;++i) t[i]+=t[i-1];
for(int i=1;i<=n;++i) sa[t[rk[i]]--]=i;
for(int k=1;;k<<=1)
{
int cnt=0;
for(int i=n-k+1;i<=n;++i) y[++cnt]=i;
for(int i=1;i<=n;++i) if(sa[i]>k) y[++cnt]=sa[i]-k;
for(int i=1;i<=m;++i) t[i]=0;
for(int i=1;i<=n;++i) t[rk[i]]++;
for(int i=1;i<=m;++i) t[i]+=t[i-1];
for(int i=n;i;--i) sa[t[rk[y[i]]]--]=y[i],y[i]=rk[i];
for(int i=1;i<=n;++i) rk[sa[i]]=(y[sa[i]]==y[sa[i-1]]&&y[sa[i]+k]==y[sa[i-1]+k])?rk[sa[i-1]]:rk[sa[i-1]]+1;
m=rk[sa[n]];if(m==n) break;
}
for(int i=1,j,k=0;i<=n;h[rk[i++]]=k) for(k?k--:0,j=sa[rk[i]-1];s[i+k]==s[j+k];++k);
}
void stpre()
{
for(int i=2;i<=n;++i) mxlg[i]=(1<<mxlg[i-1]+1)<=i?mxlg[i-1]+1:mxlg[i-1];
for(int i=1;i<=n;++i) st[i][0]=h[i];
for(int j=1;j<=mxlg[n];++j)
for(int i=1;i+(1<<j)-1<=n;++i)
st[i][j]=min(st[i][j-1],st[i+(1<<j-1)][j-1]);
}
int lcp(int x,int y)
{
if(rk[x]>rk[y]) swap(x,y);
int k=mxlg[rk[y]-rk[x]];
return min(st[rk[x]+1][k],st[rk[y]-(1<<k)+1][k]);
}
int p[N],num,v[N];
void init()
{
for(int i=2;i<=n;++i)
{
if(v[i]==0){
v[i]=i;p[++num]=i;d[i].push_back(i);
//for(int j=i;j<=n;j+=i) d[j].push_back(i);
}
for(int j=1;p[j]<=n/i;++j)
{
v[p[j]*i]=p[j];d[p[j]*i].push_back(p[j]);for(int k=0;k<d[i].size();++k) d[p[j]*i].push_back(d[i][k]);
if(i%p[j]==0) break;
}
}
}
signed main()
{
scanf("%s",s+1);
getsa();
stpre();
q=read();
for(int i=1;i<=q;++i)
{
int l=read(),r=read(),len=r-l+1;
int x=len;
for(int j=0;j<d[len].size();++j)
{
int w=len-x/d[len][j];
if(lcp(l,r-w+1)>=w) x/=d[len][j];
}
write(x);puts("");
}
return 0;
}
/*
8
aaabcabc
3
1 3
3 8
4 8
*/
posted @   glq_C  阅读(45)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效
点击右上角即可分享
微信分享提示