漏了一题可还行。。。这个显然是我不会的群论题,虽然也不用太高深的知识,可能说是找规律题更合适。
用置换的符号,可以发现
f
(
p
,
q
)
=
q
⋅
p
−
1
f(p,q)=q\cdot p^{-1}
f(p,q)=q⋅p−1,这里
⋅
\cdot
⋅指的是置换的复合。
于是有:
- a 1 = p a_1=p a1=p
- a 2 = q a_2=q a2=q
- a 3 = q p − 1 a_3=qp^{-1} a3=qp−1
- a 4 = q p − 1 q − 1 a_4=qp^{-1}q^{-1} a4=qp−1q−1
- a 5 = q p − 1 q − 1 p q − 1 a_5=qp^{-1}q^{-1}pq^{-1} a5=qp−1q−1pq−1
- a 6 = q p − 1 q − 1 p p q − 1 a_6=qp^{-1}q^{-1}ppq^{-1} a6=qp−1q−1ppq−1
- a 7 = q p − 1 q − 1 p q p q − 1 = ( q p − 1 q − 1 p ) p ( q p − 1 q − 1 p ) − 1 a_7=qp^{-1}q^{-1}pqpq^{-1}=(qp^{-1}q^{-1}p)p(qp^{-1}q^{-1}p)^{-1} a7=qp−1q−1pqpq−1=(qp−1q−1p)p(qp−1q−1p)−1
-
a
8
=
q
p
−
1
q
−
1
p
q
p
−
1
q
p
q
−
1
=
(
q
p
−
1
q
−
1
p
)
q
(
q
p
−
1
q
−
1
p
)
−
1
a_8=qp^{-1}q^{-1}pqp^{-1}qpq^{-1}=(qp^{-1}q^{-1}p)q(qp^{-1}q^{-1}p)^{-1}
a8=qp−1q−1pqp−1qpq−1=(qp−1q−1p)q(qp−1q−1p)−1
令 A = q p − 1 q − 1 p A=qp^{-1}q^{-1}p A=qp−1q−1p,那么有 a 7 = A a 1 A − 1 a_7=Aa_1A^{-1} a7=Aa1A−1, a 8 = A a 2 A − 1 a_8=Aa_2A^{-1} a8=Aa2A−1,于是容易用归纳法证明 a n = A a n − 6 A − 1 ( n > 6 ) a_n=Aa_{n-6}A^{-1}(n>6) an=Aan−6A−1(n>6)。这样可以快速知道 a k = A ⌊ k − 1 6 ⌋ a ( k − 1 ) m o d 6 + 1 ( A − 1 ) ⌊ k − 1 6 ⌋ a_k=A^{\lfloor \frac{k-1}{6}\rfloor}a_{(k-1) \bmod 6+1}(A^{-1})^{\lfloor \frac{k-1}{6}\rfloor} ak=A⌊6k−1⌋a(k−1)mod6+1(A−1)⌊6k−1⌋。
置换的复合,求逆, k k k次幂都是 O ( N ) \mathcal O(N) O(N)的,于是总时间复杂度仍为 O ( N ) \mathcal O(N) O(N)。
#include <bits/stdc++.h>
using namespace std;
bool vis[100005];
int now[100005];
struct Per {
int *num,n;
Per() {}
Per(int a):n(a) {num=new int[n+1];}
Per inv() {
Per b(n);
for(int i=1;i<=n;i++) b.num[num[i]]=i;
return b;
}
Per operator * (Per b) {
Per c(n);
for(int i=1;i<=n;i++) c.num[i]=num[b.num[i]];
return c;
}
Per operator ^ (int k) {
Per b(n);
for(int i=1;i<=n;i++) vis[i]=0;
for(int i=1;i<=n;i++)
if (!vis[i]) {
int x=i,cnt=0;
do {
now[++cnt]=x;
vis[x]=1;
x=num[x];
} while (x!=i);
for(int j=1;j<=cnt;j++) b.num[now[j]]=now[(j+k-1)%cnt+1];
}
return b;
}
};
Per fir[7];
int main() {
int n,k;
scanf("%d%d",&n,&k);
fir[1]=Per(n);
fir[2]=Per(n);
for(int i=1;i<=n;i++) scanf("%d",&fir[1].num[i]);
for(int i=1;i<=n;i++) scanf("%d",&fir[2].num[i]);
for(int i=3;i<=6;i++) fir[i]=fir[i-1]*fir[i-2].inv();
Per a=fir[2]*fir[1].inv()*fir[2].inv()*fir[1];
Per ans=(a^((k-1)/6))*fir[(k-1)%6+1]*(a.inv()^((k-1)/6));
for(int i=1;i<=n;i++) printf("%d ",ans.num[i]);
printf("\n");
return 0;
}