题解 蓝超巨星
发现可以矩阵快速幂预处理出一次递进的字符集映射
发现然后需要知道的就是要递进多少次才能变成 \(t\)
考虑那个映射的周期是 \(\mathrm{lcm}\),大约是 \(1260\) 级别的,可以接受
但是再考虑那个循环移位周期就大了去了(
那么忽略循环移位,只跑不加循环移位的递进,若某次与 \(t\) 循环同构
则根据现在应该移多少位可以列出一个 \(\pmod n\) 的和一个 \(\pmod{\mathrm{lcm}}\) 的同余方程
解出来就可以了
复杂度貌似较高,但可以通过所有数据
一个比较靠谱的做法:
枚举最终移位了多少位
通过集合 hash \((i-lst_i)*base^i\)(其中 \(lst_i\) 为上一个与 \(i\) 同类型的元素的位置)
可以知道是否可以通过对字符集进行一些变换使得当前移位过的 \(s=t\)
然后又知道了每个字符对应应该变成什么
那么可以再列出 \(26\) 个同余方程,解就行了
让 \(base\) 与 \(mod\) 互质可以利用逆元
复杂度 \(O(26^2n)\)
- 集合 hash(等价类 hash?)
可以利用 \((i-lst_i)*base^i\)(其中 \(lst_i\) 为上一个与 \(i\) 同类型的元素的位置)对等价类进行一个 hash
点击查看代码
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f3f3f3f3f
#define N 400010
#define fir first
#define sec second
#define ll long long
#define ull unsigned long long
//#define int long long
int n, a, b;
char f[N], s[N], t[N];
namespace force{
char tem[N];
void once() {
for (int i=0; i<n; ++i) tem[((i-a)%26+26)%26]=s[i];
for (int i=0; i<n; ++i) s[i]=tem[i];
for (int i=0; i<n; ++i)
for (int j=1; j<=b; ++j)
s[i]=f[s[i]-'a'];
}
void solve() {
}
}
namespace task1{
struct matrix{
int n, m;
int a[26][26];
matrix() {n=m=0; memset(a, 0, sizeof(a));}
matrix(int x, int y) {n=x; m=y; memset(a, 0, sizeof(a));}
void resize(int x, int y) {n=x; m=y; memset(a, 0, sizeof(a));}
inline int* operator [] (int t) {return a[t];}
inline void put() {for (int i=0; i<n; ++i) {for (int j=0; j<m; ++j) cout<<a[i][j]<<' '; cout<<endl;}cout<<endl;}
inline matrix operator * (matrix b) {
matrix ans(n, b.m);
for (int i=0; i<n; ++i)
for (int k=0; k<m; ++k) if (a[i][k])
for (int j=0; j<b.m; ++j) if (b[k][j])
ans[i][j]+=a[i][k]*b[k][j];
return ans;
}
}mat, tr, I;
ll ans=INF;
ull h[N], pw[N];
char g[N], tem[N];
int dsu[N], siz[N];
const ull base=13131;
inline int find(int p) {return dsu[p]==p?p:dsu[p]=find(dsu[p]);}
inline void uni(int s, int t) {if ((s=find(s))!=(t=find(t))) siz[dsu[s]=t]+=siz[s];}
inline int gcd(int a, int b) {return !b?a:gcd(b, a%b);}
inline int lcm(int a, int b) {return a/gcd(a, b)*b;}
inline ull hashing(int l, int r) {return h[r]-h[l-1]*pw[r-l+1];}
inline matrix qpow(matrix a, ll b) {matrix ans=I; for (; b; a=a*a,b>>=1) if (b&1) ans=ans*a; return ans;}
void exgcd(ll a, ll b, ll& x, ll& y) {
if (!b) {x=1; y=0; return ;}
exgcd(b, a%b, y, x);
y-=a/b*x;
}
ll excrt(vector<pair<ll, ll>> sta) {
ll rest=sta[0].fir, lcm=sta[0].sec;
ll x1, x2, g=gcd(lcm, sta[1].sec);
exgcd(lcm, sta[1].sec, x1, x2);
if ((sta[1].fir-rest)%g) return INF;
x1=x1*((sta[1].fir-rest)/g);
rest=rest+x1*lcm;
lcm=lcm/gcd(lcm, sta[1].sec)*sta[1].sec;
rest=(rest%lcm+lcm)%lcm;
return rest;
}
void force_solve() {
for (int ans=1; clock()<900000; ++ans) {
for (int i=0; i<n; ++i) tem[((i-a)%n+n)%n]=s[i];
for (int i=0; i<n; ++i) s[i]=tem[i];
for (int i=0; i<n; ++i) s[i]=g[tem[i]];
// for (int i=0; i<n; ++i)
// for (int j=1; j<=b; ++j)
// s[i]=f[s[i]]-'a';
// cout<<"s: "; for (int i=0; i<n; ++i) cout<<(char)(s[i]+'a')<<' '; cout<<endl;
for (int i=0; i<n; ++i) if (s[i]!=t[i]) goto jump;
printf("%d\n", ans); exit(0);
jump: ;
}
puts("-1"); exit(0);
}
void solve() {
I.resize(26, 26);
for (int i=0; i<26; ++i) I[i][i]=1;
tr.resize(26, 26);
for (int i=0; i<26; ++i) tr[i][f[i]-'a']=1;
mat.resize(1, 26);
for (int i=0; i<26; ++i) mat[0][i]=i;
mat=mat*qpow(tr, b);
for (int i=0; i<26; ++i) g[mat[0][i]]=i;
// a%=26;
for (int i=0; i<n; ++i) s[i]-='a', t[i]-='a';
for (int i=0; i<26; ++i) siz[dsu[i]=i]=1;
for (int i=0; i<26; ++i) uni(i, g[i]);
int T=1;
for (int i=0; i<26; ++i) if (find(i)==i) T=lcm(T, siz[i]);
// cout<<"T: "<<T<<endl;
pw[0]=1;
for (int i=1; i<=2*n; ++i) pw[i]=pw[i-1]*base;
ull tem=0;
for (int i=0; i<n; ++i) tem=tem*base+t[i];
// if (n<=300) force_solve();
ll tlcm=lcm(n, T);
for (int i=1; i<=T; ++i) {
for (int j=0; j<n; ++j) s[j]=g[s[j]];
// cout<<"s: "; for (int i=0; i<n; ++i) cout<<(char)(s[i]+'a')<<' '; cout<<endl;
for (int j=1; j<=n; ++j) h[j]=h[j-1]*base+s[j-1];
for (int j=n+1; j<=2*n; ++j) h[j]=h[j-1]*base+s[j-n-1];
for (int j=1; j<=n; ++j) if (hashing(j, j+n-1)==tem) {
// cout<<"ij: "<<i<<' '<<j<<endl;
// cout<<"s: "; for (int i=0; i<n; ++i) cout<<(char)(s[i]+'a')<<' '; cout<<endl;
int need=j-1;
// cout<<"need: "<<need<<endl;
for (int now=0; now<n; ++now) if (1ll*a*now%n==need) {
// cout<<now<<' '<<n<<','<<i<<' '<<T<<endl;
ll tem=excrt({{now, n}, {i, T}});
// cout<<"tem: "<<tem<<endl;
ans=min(ans, tem?tem:tlcm);
}
}
}
printf("%lld\n", ans==INF?-1ll:ans);
}
}
signed main()
{
freopen("blue.in", "r", stdin);
freopen("blue.out", "w", stdout);
scanf("%d%d%d", &n, &a, &b);
scanf("%s%s%s", f, s, t);
// force::solve();
task1::solve();
return 0;
}