zoukankan      html  css  js  c++  java
  • HKE和他的小朋友(矩乘快速幂)

    题面:

    题目背景:

    HKE带着 $ n $ 个小朋友做游戏

    题目描述:

    现在有n个座位编号为 $ 1 $ 至 $ n $ ,这些小朋友也编号 $ 1 $ 至 $ n $ 。一开始所有小朋友都坐在相应的座位上。HKE的游戏可用一个n的排列 $ A(A_1,A_2cdots A_n $ )表示。一轮游戏时,对于所有的 $ 1leq ileq n $ ,坐在位置 $ i $ 上的小朋友坐到位置 $ A_i $ 上

    现在游戏进行了 $ k $ 轮,HKE想知道游戏结束后,位置 $ 1,2cdots n $ 分别坐了几号小朋友?

    输入格式:

    第一行 $ n,k $ 。

    第二行 $ A_1,A_2cdots A_n $

    输出格式:

    一行n个数表示 k 轮游戏后坐在位置 $ 1,2……n $ 上的小朋友的编号

    输入样例#1:

    5 5
    2 3 1 5 4
    

    输出样例#1:

    2 3 1 5 4
    

    输入样例#2:

    5 4
    2 3 1 5 4
    

    输出样例#2:

    3 1 2 4 5
    

    数据范围:

    30%的数据, $ nleq1000 $ , $ kleq1000 $

    100%的数据, $ nleq100000 $ , $ kleq2^{31}-1 $

    本题 $ solution $ :

    首先请允许我奶一波:本题出的是真的好!

    某蒟蒻心路历程:

    小文:这不是矩阵快速幂裸题吗?!!

    题面:矩阵快速幂复杂度 $ n^3 $ OK?

    小文:那就降到二维 $ n^2 $ 优化麻!!!

    题面:.... $ nleq100000 $ ,are you sure?

    小文:我 &% $ &#%&#% !!!!!!!

    于是乎让我再仔细看看题目吧:

    解 1 :跑图论求环

    我们(在脑海里)建一个图,将第 i 步的结果与第 i+1 步的结果用一条边连起来,跑一遍你会发现这是一个环(即你不断转换下去会回到你的初始状态。所以你将 k mod 一下环的大小( $ leq n $ )然后跑一遍图即可。(稍稍维护一下复杂度)

    这对蒟蒻来说太难了,于是就没有代码实现了

    解 2 :快速幂

    这题其实不存在矩阵成分(有启发效果),重点在与快速幂和你的转移过程

    原理:

    1.转移的结合律:

    下文中但凡以 2 3 1 5 4(一个栗子)为标准转移,2 3 1 5 4 分别表示 $ A_1 $ $ A_2 $ $ A_3 $ $ .... $ $ A_5 $ :

    转移的实现:

    inline void ans(){ //给ans数组转换
    	for(rg i=1;i<=n;++i) c[i]=a[i];
    	for(rg i=1;i<=n;++i) a[b[i]]=c[i];
    }
    

    对于一个以 2 3 1 5 4 为标准的转移,我们若转移两次,就相当于进行一次以 3 1 2 4 5 为标准的转移(不信试试);而我们若转移 3 次,就相当于先进行一次以 3 1 2 4 5 为标准的转移在进行一次以 2 3 1 5 4 为标准的转移。这说明小朋友换位置具有结合律,这是我们快速幂的基础。

    而 3 1 2 4 5 是可以通过 2 3 1 5 4 推出来的(类似矩阵乘法):

    $ egin{vmatrix}2 &3&1&4&5\2&3&1&4&5|&|&|&|&|\3&1&2&4&5end{vmatrix} $ $

    看的出怎么推吗:先讲一下 3 是如何来的:

    首先 3 的意义表示 1 号小朋友在转移两次后在 3 号位置。所以我们看到 1 号小朋友第一轮转换时要转换到 2 号位置,而第二轮转换时 2 号位置的人要转换到 3 号位置,所以就相当于一号小朋友在转移两次后要在 3 号位置。 1 2 4 5 也是这样得来的:实现:

    inline void base(){ //给bese数组转换
    	for(rg i=1;i<=n;++i) c[i]=b[i];
    	for(rg i=1;i<=n;++i) b[i]=c[c[i]];
    }
    

    而此时如果我们需要以2 3 1 4 5为标准转移 4 次,就可以直接以 3 1 2 4 5为标准转移两次即可。同样我们还可以用 3 1 2 4 5来推出一个序列,以次序列为标准转移就能直接得到以2 3 1 4 5转移 4 次的结果。

    然后直接快速幂求解即可!

    代码实现:

    以某一转换序列来推出下一个转换序列,我们用base函数实现。

    以某一序列为标准转移,我们用ans函数实现。(这两个不一样!!

    #include<iostream>
    #include<cstdio>
    #include<iomanip>
    #include<algorithm>
    #define rg register int
    
    using namespace std;
    
    int n,k;
    int b[100001];// base
    int a[100001];// answer
    int c[100001];// 借来转换赋值
    
    inline int qr(){ char ch; // 快读
    	while((ch=getchar())<'0'||ch>'9');
    	int res=ch^48;
    	while((ch=getchar())>='0'&&ch<='9')
    		res=res*10+(ch^48);
    	return res;
    }
    
    inline void ans(){ //给ans数组转换
    	for(rg i=1;i<=n;++i) c[i]=a[i];
    	for(rg i=1;i<=n;++i) a[b[i]]=c[i];//重点1
    }
    
    inline void base(){ //给bese数组转换
    	for(rg i=1;i<=n;++i) c[i]=b[i];
    	for(rg i=1;i<=n;++i) b[i]=c[c[i]];//重点2
    }
    
    int main(){
    	n=qr();k=qr();
    	for(rg i=1;i<=n;++i)
    		b[i]=qr(),a[i]=i;//赋初值
    	while(k){
    		if(k&1)ans();
    		base();k>>=1;
    	}// 快速幂
    	for(rg i=1;i<=n;++i)
    		printf("%d ",a[i]);//输出ans
    	return 0;
    }
    

    本题重在理解,码量其实不高(除去快读等....

    $ O_{(nlog{n})} $ 的复杂度加上码量还是很优秀的。

    注:题目来源:华南师范大学附属中学,洛谷Noip热身赛

  • 相关阅读:
    React在componentDidMount里面发送请求
    React 术语词汇表
    React里受控与非受控组件
    React和Vue等框架什么时候操作DOM
    【LeetCode】79. Word Search
    【LeetCode】91. Decode Ways
    【LeetCode】80. Remove Duplicates from Sorted Array II (2 solutions)
    【LeetCode】1. Two Sum
    【LeetCode】141. Linked List Cycle (2 solutions)
    【LeetCode】120. Triangle (3 solutions)
  • 原文地址:https://www.cnblogs.com/812-xiao-wen/p/10332491.html
Copyright © 2011-2022 走看看