*题解:P3538 [POI 2012] OKR-A Horrible Poem
解析
如果你还不会利用哈希 \(O(n)\) 找循环节,那么你应该先去做 P4391。
由于我们要求的是完整周期,所以循环节长度必定为所选片段长度的因子,于是可以很轻松地得到一个 \(O(q \sqrt n)\) 的做法。
设查询的字符串为 \(a\)。观察到若字符串 \(b\) 是一个完整周期,则对于所有满足 \(k \cdot \operatorname{len}(b) \mid \operatorname{len}(a)\) 的 \(k\),\(b^k\) 也是一个完整周期。
设 \(c\) 为最短完整周期且 \(c^x=a\),很多题解到这里就直接开始对 \(x\) 分解质因数了,具体地,维护一个当前答案 \(ans\),初始为 \(\operatorname{len}(a)\),对于 \(\operatorname{len}(a)\) 的每个质因子 \(d\),判断 \(c[1,\dfrac{ans}{d}]\) 是否是一个完整周期,如果是,则令 \(ans \gets \dfrac{ans}{d}\)。
但实际上还需要说明除的时候不会把 \(\operatorname{len}(c)\) 的质因子除掉。事实上,不存在一个字符串 \(d\) 使得 \(d\) 是 \(a\) 的完整周期且 \(c\) 不是 \(d\) 的完整周期。使用周期引理可以轻松地证明这个命题。
周期引理:若 \(p,q\) 是字符串 \(S\) 的两个周期且 \(p + q \le \operatorname{len}(S) +\gcd(p,q)\),则 \(\gcd(p,q)\) 也是 \(S\) 的一个周期。
所以如果存在这样的 \(d\) 则必定存在一个长度为 \(\gcd(\operatorname{len}(c),\operatorname{len}(d))\) 的完整周期,原命题得证。
在线性筛素数的同时处理出每个数的最小质因子,我们就得到了一个时间复杂度 \(O(q \log n)\) 的做法。
代码
/*
*/
#include<bits/stdc++.h>
#define eps 0.000001
#define mid ((l + r) >> 1)
#define ls(x) ((x) << 1)
#define rs(x) (((x) << 1) | 1)
using namespace std;
typedef unsigned long long ull;
typedef long long ll;
typedef pair<ll,int> pii;
const int N = 5e5 + 5,M = 3.2e4 + 5,base = 13331;
ull h[N],mi[N];
vector<int> v[N];
bool vis[N];
vector<int> pri;
int d[N];
void euler(){
for(int i=2;i<N;i++){
if(!vis[i]){
d[i] = i;
pri.push_back(i);
}
for(int j=0;j<pri.size() && i * pri[j] < N;j++){
vis[i * pri[j]] = true;
d[i * pri[j]] = pri[j];
if(i % pri[j] == 0){
break;
}
}
}
}
ull get(int l,int r){
return h[r] - h[l - 1] * mi[r - l + 1];
}
bool chk(int l,int r,int k){
if(!k) return false;
return get(l,r - k) == get(l + k,r);
}
int calc(int l,int r){
int len = r - l + 1;
int res = len,now = len;
while(now > 1){
if(chk(l,r,res / d[now])){
res /= d[now];
}
now /= d[now];
}
return res;
}
int main(){
// freopen("in.txt","r",stdin);
// freopen("out1.txt","w",stdout);
ios::sync_with_stdio(false);
cin.tie(0),cout.tie(0);
euler();
int n;
cin>>n;
string s;
cin>>s;
s = " " + s;
mi[0] = 1;
for(int i=1;i<s.size();i++){
mi[i] = mi[i - 1] * base;
h[i] = h[i - 1] * base + s[i];
}
int q;
cin>>q;
while(q--){
int a,b;
cin>>a>>b;
cout<<calc(a,b)<<'\n';
}
return 0;
}

浙公网安备 33010602011771号