AGC031 D A Sequence of Permutations

题意

定义f(p,q)=r,(p,q,r都是排列)满足
r p i = q i r_{p_i}=q_i rpi=qi
然后给出 a 1 , a 2 a_1,a_2 a1,a2,且 a n + 2 = f ( a n , a n + 1 ) a_{n+2}=f(a_n,a_{n+1}) an+2=f(an,an+1)
a k a_k ak
n<=1e5,k<=1e9

题解

我们定义两个排列的乘法为
p*q=r,当
r i = p q i r_i=p_{q_i} ri=pqi
那么显然,这个乘法不满足交换律
但是聪明的读者一定发现了这个乘法是满足结合律的
(具体怎么证?你可以表示出来(ab)c,再表示出来a(bc)来证)
这个乘法的单位元就是id,也即 A i = i A_i=i Ai=i
(自然我们也就可以得到逆元的定义了: A A i − 1 = i A^{-1}_{A_i}=i AAi1=i
此外呢还有一点, ( p q ) − 1 = q − 1 p − 1 (pq)^{-1}=q^{-1}p^{-1} (pq)1=q1p1(注意换了顺序)
不严谨证明见下:

我们令左边为A,则 A p q i = i A_{p_{q_i}}=i Apqi=i
B = q − 1 B=q^{-1} B=q1,则 B q i = i B_{q_i}=i Bqi=i
C = p − 1 C=p^{-1} C=p1,则 C p i = i C_{p_i}=i Cpi=i
令右边为D,则 D i = B C i D_i=B_{C_i} Di=BCi,那么我们令 i = p i i=p_i i=pi就有 D p i = B i D_{p_i}=B_i Dpi=Bi,那么类似地有 D p q i = i D_{p_{q_i}}=i Dpqi=i
那么A=D,证毕

然后题目所给的 f ( p , q ) f(p,q) f(p,q),就 = q p − 1 =qp^{-1} =qp1(证明可用类似上面的方法)
那么我们就可以愉快地打表了
来自官方题解
Patience is important in this experiment.(官方题解说的)
em…然后我们可以把这个a写成 A B A − 1 ABA^{-1} ABA1的形式(A、B是两个新的排列)
那么我们再打表打出A B
在这里插入图片描述
(注意我们如果把(A7,B7)写成 ( q p − 1 q − 1 , p ) (qp^{-1}q^{-1},p) (qp1q1,p)也是没问题的,但是这样我们就找不出来规律了)
嗯…
然后我们(根据规律)把A表示成 ( q p − 1 q − 1 p ) t C ( t = ⌊ k − 1 6 ⌋ ) (qp^{-1}q^{-1}p)^tC (t=\lfloor\frac{k-1}{6}\rfloor) (qp1q1p)tC(t=6k1)
可以发现,C和B都是6为周期的
然后就快速幂计算那一坨,再打表搞出来B C即可算出A,然后即可算出 a k a_k ak

综上,这是一道找规律神题…

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
const int N=1e5+6;//!
struct permutation{
    int a[N];
    permutation(){memset(a,0,sizeof a);}
    int& operator [](int x){return a[x];}
}p,q,ip,iq,A,B,ans;
int n,k;
permutation operator *(permutation a,permutation b){
    permutation c;
    for(int i=1;i<=n;i++)
        c[i]=a[b[i]];
    return c;
}
permutation inv(permutation a){
    permutation b;
    for(int i=1;i<=n;i++)
        b[a[i]]=i;
    return b;
}
permutation operator ^(permutation a,int b){
    permutation c;
    for(int i=1;i<=n;i++)
        c[i]=i;
    while(b){
        if(b&1)
            c=c*a;
        a=a*a;
        b>>=1;
    }
    return c;
}
void Print(permutation x){
    for(int i=1;i<=n;i++)
        printf("%d ",x.a[i]);
    puts("");
}
int main()
{
    scanf("%d%d",&n,&k);
    for(int i=1;i<=n;i++)
        scanf("%d",&p[i]);
    for(int i=1;i<=n;i++)
        scanf("%d",&q[i]);
    ip=inv(p);
    iq=inv(q);
    int f=(k-1)/6,g=k-f*6;
    permutation h=q*ip*iq*p;
    A=h^f;
    if(g==1){
        B=p;
    }
    else if(g==2){
        B=q;
    }
    else if(g==3){
        B=q*ip;
    }
    else if(g==4){
        A=A*q;
        B=ip;
    }
    else if(g==5){
        A=A*q*ip;
        B=iq;
    }
    else{
        A=A*q*ip;
        B=iq*p;
    }
    ans=A*B*inv(A);
    Print(ans);
}

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值