题目
思路
注意到f 相当于是对原来的字符串应用了一个置换p(即f(S)pi = Si),我们把
p 写出来。
考虑p 中的环(如果你不知道这是什么,请参考Day 4 第一题的题目描述),可
以发现应用一次变换相当于是所有字母沿着这个环“走”了一步。
那么我们可以对于每个环,将环上的字母倍长后运行一次KMP 算法,得到所有
的匹配位置。
显然对于某个环而言,这个匹配位置必须是一个等差数列。设首项为t 公差为d,
则我们相当于要求答案mod d 必须为t。
接下来,我们需要证明一个结论,该结论可以很容易地通过打表观察得到:
定理3.1. 所有环长的最小公倍数不超过n。
因为所有环长的最小公倍数不超过n,所以转这么多之后一定会回去,所以如果
有解那么答案不超过n。
于是,我们可以处理出对于每个d 要求的余数md,然后将md,md+d,md+2d, · · ·
打上一个d 的标记,最后第一个有所有d 标记的数字就是答案了。
代码
#include<bits/stdc++.h>
using namespace std;
int n,sz,maxn,ind;
int in[1000005],at[1000005];
char t[1000005],s[1000005];
vector<int> vec[1000005];
bool vis[1000005],ok[1000005];
bool work(int x) {
for(int i=2;i<n;i++) if(t[vec[in[i]][(at[i]+x)%vec[in[i]].size()]]!=s[i]) return 0;
return 1;
}
int main() {
scanf("%d%s%s",&n,s+1,t+1);
if(s[1]!=t[1]||s[n]!=t[n]) {
printf("-1\n");
return 0;
}
for(int i=2;i<n;i++)
if(!vis[i]) {
sz++;
vec[sz].push_back(i);
in[i]=sz;
vis[i]=1;
at[i]=0;
for(int j=i&1?(i+1)/2:i/2+n/2;j!=i;j=j&1?(j+1)/2:j/2+n/2) {
vec[sz].push_back(j);
vis[j]=1;
in[j]=sz;
at[j]=vec[sz].size()-1;
}
}
for(int i=1;i<=sz;i++)
if(vec[i].size()>maxn) {
maxn=vec[i].size();
ind=i;
}
char ch=s[vec[ind][0]];
for(int i=1;i<=n;i++) if(t[i]==ch) ok[i]=1;
for(int i=0;i<maxn;i++)
if(ok[vec[ind][i]])
if(work(i)) {
printf("%d\n",i);
return 0;
}
printf("-1\n");
return 0;
}