P3538 [POI2012]OKR-A Horrible Poem


给定一个串和多个区间,要求出区间最短循环节长度

1.判断一个字符串是该区间的循环节,可以O(1)hash判定,设枚举的循环节长度为t,判断[l,r-t]与[l+t,r]相等否即可
2.长度x是区间的一个循环节,y是x的倍数且是区间长度的约数,那么y也是循环节
3.对于多组询问的分解质因数,我们不需要全部预处理出来,也不需要每次都用试除法去试,我们可以用求出每个数的最小质因子设为v[x],然后用x=x/v[x],这些v[x]就是原数x的质因子集合,比试除法快很多

typedef unsigned long long ull;
const int N = 5e5 + 79;
const ull base = 13131;
int n, x, y, q;
ull p[N], H[N];
char s;
inline bool check(int l, int r, int x, int y) {
	return H[r] - H[l - 1] * p[r - l + 1] == H[y] - H[x - 1] * p[y - x + 1];
}


int v[N],prime[N],t;
inline void EulerSieve(int mx){
	rep(i,2,mx){
		if(!v[i]){
			v[i]=i;
			prime[++t]=i;
		}
		rep(j,1,t){
			if(1ll*prime[j]*i>mx||prime[j]>i) break;
			v[i*prime[j]]=prime[j];
		}
	}
}

int a[N];
inline void solve(int x, int y) {
	int len = y - x + 1;
	int cnt=0;
	while(len != 1) {
		a[++cnt] =v[len];
		len/=v[len];
	}
	len=y-x+1;
	rep(i,1,cnt){
		int t=len/a[i];//μ¥???-?·?ú3¤?è 
		if(check(x,y-t,x+t,y) ){
			len/=a[i];
		}
	}
	out(len,'\n');
}

int main() {
	read(n);
	p[0] = 1;
	rep(i, 1, n) {
		while((s = gt()) < 'a' || s > 'z');
		p[i] = p[i - 1] * base;
		H[i] = H[i - 1] * base + s;
	}
	EulerSieve(n);
	read(q);
	while(q--) {
		read(x);
		read(y);
		solve(x, y);
	}
	return 0;
}