前言
比较典,可以当模板题,故记录一下,写的可能比较水。
题意
Link
长度为 \(n\ (\leq 6\times 10^5)\) 的字符串,有 \(q\ (\leq 2\times 10^6)\) 个询问,每次询问求一个区间的最小循环节。
思路
题面看起来很唬人,我们平时求最短循环节都是用前缀函数,这一放在区间上就不会做了。
但实际上很简单,最小循环节的长度一定是串长的因数,因此直接枚举即可,用线性筛记录每个数最大的质因数来优化,不断除以自己最大的质因数即可枚举所有因数。
至于判断一个长度是否为循环节,可以用哈希,设长度为 \(len\),如果 \(\operatorname{Substr}[l,r-len]=\operatorname{Substr}[l+len,r]\) 则说明该长度为循环节长度。
复杂度当然就是 \(O(q\cdot d(n))\),这个 \(d(n)\) 就很玄学,据说可以证明最多 \(O(\sqrt n)\),但实际经常跑不满,反正卡常题。
代码
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int MAXN=5e5,MAXQ=2e6;
LL bs=13131,bspw[MAXN+5],P=1e9+321;
int n,q;
char str[MAXN+5];inline void init_bspw(){bspw[0]=1;for(int i=1;i<=n;i++)bspw[i]=bspw[i-1]*bs%P;
}
struct HashNode{LL val;int len;HashNode(){}HashNode(LL a,int b):val(a),len(b){}
};
inline HashNode operator + (const HashNode& a,const HashNode& b){HashNode res;res.val=(a.val*bspw[b.len]%P+b.val)%P;res.len=a.len+b.len;return res;
}
inline HashNode operator - (const HashNode& a,const HashNode& b){//b is prefix of aHashNode res;res.val=(a.val-b.val*bspw[a.len-b.len]%P+P)%P;res.len=a.len-b.len;return res;
}
inline bool operator == (const HashNode& a,const HashNode& b){return (a.len==b.len) && (a.val==b.val);
}
class HashString{
private:HashNode hs[MAXN+5];
public:inline void build(){hs[0]=HashNode(0,0);for(int i=1;i<=n;i++)hs[i]=HashNode(str[i]-'a'+1,1);for(int i=1;i<=n;i++)hs[i]=hs[i-1]+hs[i];}inline HashNode query(const int& l,const int& r) const{return hs[r]-hs[l-1];}
}hs;vector<int>prime;
bool vis[MAXN+5];
int divisor[MAXN+5];
inline void init_prime(){for(int i=2;i<=n;i++){if(!vis[i]) prime.push_back(i),divisor[i]=i;for(auto it:prime){if(1LL*it*i>n) break;vis[it*i]=true;divisor[it*i]=it;if(i%it==0) break;}}
}inline bool check(int l,int r,int len){return hs.query(l,r-len)==hs.query(l+len,r);
}int main(){scanf("%d",&n);scanf("%s",str+1);init_bspw();init_prime();hs.build();scanf("%d",&q);int l,r,len,tmp;while(q--){scanf("%d %d",&l,&r);len=tmp=r-l+1;while(tmp>1){if(check(l,r,len/divisor[tmp])) len/=divisor[tmp];tmp/=divisor[tmp];}printf("%d\n",len);}return 0;
}