Just Shuffle——2020牛客暑期多校训练营(第二场)J题

Just Shuffle——2020牛客暑期多校训练营(第二场)J题

    • 题目描述
    • 输入描述
    • 输出描述
    • 输入
    • 输出
    • 题解
      • 1.[逆元](https://blog.csdn.net/Harington/article/details/96310239)(一般以[扩展欧几里得,费马小定理或欧拉定理,特例,打表等方法求解](https://blog.csdn.net/guhaiteng/article/details/52123385))
      • 2.[置换群快速幂](https://wenku.baidu.com/view/0bff6b1c6bd97f192279e9fb.html)(3.1.a中可以得到长度与指数互质时的分数幂运算的过程是,目标循环每次指针向后移k位,源循环每次向后移1位)
    • AC代码
      • 官方解法](https://ac.nowcoder.com/acm/contest/view-submission?submissionId=44194820)(来自大佬[乐正绫ovo
      • 暴力求逆元
      • 置换群快速幂](https://ac.nowcoder.com/acm/contest/view-submission?submissionId=44192023)(来自大佬[Alchemist

题目描述

Given a permutation with size n and an integer k, you should find a permutation substitution P that {1,2,⋯,n} will become A after performing substitution P for exactly k times. Print the permutation after performing P for once on {1,2,⋯,n}. If there are multiple solutions, print any of them. If there is no solution, print “-1” in one line.

输入描述

Just Shuffle——2020牛客暑期多校训练营(第二场)J题_第1张图片

输出描述

If there exists solutions, print n integers in one line, or print “-1” in one line.

输入

3 998244353
2 3 1

输出

3 1 2

题解

本题有两种解法:

1.逆元(一般以扩展欧几里得,费马小定理或欧拉定理,特例,打表等方法求解)

2.置换群快速幂(3.1.a中可以得到长度与指数互质时的分数幂运算的过程是,目标循环每次指针向后移k位,源循环每次向后移1位)

(以下是官方题解)
在这里插入图片描述

AC代码

官方解法(来自大佬乐正绫ovo)

#include
#define pb push_back
#define mp make_pair
#define fi first
#define se second
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair pii;
typedef pair pll;
template  bool chkmax(T &x,T y){return x bool chkmin(T &x,T y){return x>y?x=y,true:false;}
 
int readint(){
    int x=0,f=1; char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
int n,k;
int a[100005],ans[100005];
bool vis[100005];
 
void exgcd(int x,int y,int &a,int &b){
    if(!y){
        a=1,b=0;
        return;
    }
    exgcd(y,x%y,b,a);
    b-=a*(x/y);
}
int main(){
    n=readint(); k=readint();
    for(int i=1;i<=n;i++) a[i]=readint();
    for(int i=1;i<=n;i++){
        if(vis[i]) continue;
        vis[i]=1;
        vector v(0);
        v.pb(i);
        for(int j=a[i];!vis[j];j=a[j]) v.pb(j),vis[j]=1;
        int tmp=k%v.size(),x,y;
        exgcd(tmp,v.size(),x,y);
        if(x<0) x+=v.size();
        for(int j=0;j

暴力求逆元

#include
using namespace std;
int vis[100007],a[100007],b[100007],n,k;vectorlo;
int main()
{
    cin>>n>>k;for(int i=1;i<=n;i++)cin>>a[i];
    for(int i=1;i<=n;i++)if(!vis[i]){lo.clear();int x=a[i];while(!vis[x])vis[x]=1,lo.push_back(x),x=a[x];int r=lo.size(),inv;for(int i=0;i

置换群快速幂(来自大佬Alchemist)

#include 
#include 
#include 
 
using namespace std;
 
int n, k, a[100005], ans[100005];
bool vis[100005];
 
void getCircle(int x) {
    vector V;
    V.push_back(x);
    x = a[x];
    while (x != V[0]) {
        V.push_back(x);
        vis[x] = true;
        x = a[x];
    }
    int r = k % (int) V.size();
    vector R(V.size());
    for (int i = 0; i < V.size(); i++)
        R[(i * r) % V.size()] = V[i];
    for (int i = 0; i < V.size(); i++)
        ans[R[i]] = R[(i + 1) % V.size()];
}
 
int main() {
    scanf("%d%d", &n, &k);
    for (int i = 1; i <= n; i++)
        scanf("%d", &a[i]);
    for (int i = 1; i <= n; i++)
        if (!vis[i])
            getCircle(i);
    for (int i = 1; i < n; i++)
        printf("%d ", ans[i]);
    printf("%d", ans[n]);
    return 0;
}

你可能感兴趣的:(Just Shuffle——2020牛客暑期多校训练营(第二场)J题)