[POI2012]OKR-A Horrible Poem

这里是题面

先放一下做这道题可能要用到的几个性质 :

 _ 循环节一定是总长度的约数
 _ 若字符串s有一个循环节k,则k * i也是s的循环节
 _n是[l,r]这一段的循环节  的充要条件是  [l,r-n]和[l+n,r]相同(可以感性理解一下em)

知道这几点之后,就可以做这道题啦!୧(๑•̀⌄•́๑)૭

假设此时我们要处理一个长度为\(len\)的字符串\(s\), 当前找到了一个\(s\)的循环节\(ans\)

那么我们再继续找\(ans\)的循环节,如果能找到的话,那这个\(ans\)的循环节一定也是\(s\)的循环节的

这么一直找啊找,最后就可以找到最短循环节啦em

具体的操作流程:
首先将\(ans\)初值赋为\(len\)(因为最长的循环节长度一定是\(len\)), 枚举\(len\) 的质因数(假设此时枚举到了\(x\)

\(ans/x\)是循环节,则将ans 更新成\(ans/ x\)

#include <bits/stdc++.h>
using namespace std;
#define ull unsigned long long 
const int N = 5e5 + 5;
const int Q = 2e6 + 5;

int n, q, cnt;
string sa;
int prime[N], is_prime[N];
ull h[N], power[N];

bool check(int len, int l, int r) {
	ull x = h[r - len] - h[l - 1] * power[r - len - l + 1];
	ull y = h[r] - h[l + len - 1] * power[r - len - l + 1];
	return x == y;
}
inline int read() {
	int x = 0; char c = getchar(); bool f = 1;
	while(c < '0' || c > '9') { if(c == '-') f = !f; c = getchar(); }
	while(c >= '0' && c <= '9') { x = x * 10 + c - '0'; c = getchar(); }
	return f ? x : -x;
}
int main() {
	cin >> n >> sa;
	power[0] = 1;
	for(int i = 1; i <= n; i++) {
		h[i] = h[i - 1] * 233 + sa[i - 1];
		power[i] = power[i - 1] * 233;
	}
	q = read();
	for(int i = 1; i <= q; i++) {
		int l = read();
		int r = read();
		int len = r - l + 1;
		int ans = len;
		int x = 2;
		while(len != 1 && x <= len) {
			while(ans % x == 0 && check(ans / x, l, r)) ans /= x;
			while(len % x == 0) len /= x;
			x++;			
		}
		printf("%d\n", ans);
	}
	return 0;
}
posted @ 2020-12-20 21:00  月夭  阅读(78)  评论(0编辑  收藏  举报