1 条题解

  • 0
    @ 2025-8-24 21:35:22

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar distantlight
    **

    搬运于2025-08-24 21:35:22,当前版本为作者最后更新于2019-11-16 17:09:48,作者可能在搬运后再次修改,您可在原文处查看最新版

    自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多

    以下是正文


    《潘震皓:置换群快速幂运算研究与探讨》(2005年国集论文)里面有详细说这题。本质上上一个置换开方问题,每洗牌一次,相当于把置换平方以下,总共2^s次,所以逆运算就是把置换p1..pn开2^s次方

    由于n是奇数,gcd(2^s,n)=1,并且根据题意,这个置换是一个轮换(只有一个循环节),根据论文所属,在此情况下置换开方有唯一解,并且可以在O(n)搞定。大致思路如下:

    1.将p写成轮换形式,设为a1..an 2.倒推k=2^s次方根的轮换b1..bn,根据论文,有b[1+(i-1)*k]=a[i](下标都在模n的意义下) 3.由b再倒推出置换x

    关键的第二步,原文有图,洛谷传图实在是不方便。。自己去找原文吧。。

    附代码

    #include <bits/stdc++.h>
    using namespace std;
    const int N=1009;
    int n,s,x[N],p[N],A[N],B[N],z=1;
    int main(){
        scanf("%d%d",&n,&s);
        for (int i=1;i<=n;i++) scanf("%d",&p[i]);
        for (int i=1,j=1;i<=n;i++,j=p[j]) A[i]=p[j];
        for (int i=1;i<=s;i++) z=(z*2)%n;
        for (int i=1,j=1;i<=n;i++,j=(j+z-1)%n+1) B[j]=A[i];
        for (int i=1;i<=n;i++) x[B[i]]=B[i%n+1];
        for (int i=1;i<=n;i++) cout<<x[i]<<" ";
        return 0;
    }
    
    • 1

    信息

    ID
    1226
    时间
    1000ms
    内存
    125MiB
    难度
    5
    标签
    递交数
    0
    已通过
    0
    上传者