洛谷P5151 HKE与他的小朋友 快速幂/图论+倍增

时间:2024-12-27 13:35:32

正解:矩阵快速幂/tarjan+倍增

解题报告:

传送门!

跟着神仙做神仙题系列III

这题首先一看到就会想到快速幂趴?就会jio得,哦也不是很难哦

然而,看下数据范围,,,1×105,,,显然开不下TT

所以考虑优化快速幂(或找环+倍增

两种方法都港下趴

先说图论好辣QwQ

大概是这样的:

首先我们把每个座位都抽象成一个点,由它给我的A[]可以知道坐在每个座位上的人会移到哪儿

我们就可以理解为连了一条边

显然的是我们可以换了很多次之后换回来,于是就成了一个环了

然后我们就求一波强连通分量,这样我们读入k之后就能先给他取个膜让k控制在一定范围内嘛

然后之后再用下倍增的思想,这个我jio得还是挺好懂的?就是f[i][j]表示i这个点移动2<<j之后会去哪儿

然后就好辣!

get?

快速幂其实也不难,尝试理解一下就能get

这个实在没什么好说的大概扯下趴,,,

这样的,显然它是满足结合律的,举个eg,假如我要挪21次

那我可以一次一次挪,但这显然比较慢,但我也可以这样子:21=24+22+21

所以就用和快速幂一样的思想,这么想吼,一样是有个tmp有个ans

首先20系数是0,所以ans不变,tmp变成A[tmp]

然后21系数是1,所以ans变成A[tmp],tmp变成A[tmp]

然后22系数是1,所以ans变成A[tmp],tmp变成A[tmp]

然后23系数是0,所以ans不变,tmp变成A[tmp]

然后24系数是1,所以ans变成A[tmp],tmp变成A[tmp]

这个我jio得还是可以理解的趴?挺显然的?

实在无法理解可以结合一下前面的倍增,其实这个和倍增是一样的不过倍增是预处理就成立逆推而这个是顺推而已(所以倍增会快一些,不过这个简单打一些啊QwQ

(话说这题我jio得就是单纯的快速幂啊,,,哪里是矩阵快速幂了,,,为什么我看到的两篇都是说是矩阵快速幂啊,,,没有get?

顺便一提,这题的法二有个很新颖的名词"群",似乎用那个更好解释

然而我还没学:D基础都没落实完的菜菜灵巧不配学新芝士呜呜呜

所以详见hl的博客

over!

然后两个方法的代码应该都会打的到时候都放上来QwQ

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define rg register
#define rp(i,x,y) for(register ll i=x;i<=y;++i) const ll N=;
ll n,k,a[N],nw[N],tmp[N]; ll read()
{
rg char ch=getchar();rg ll x=;rg bool y=;
while(ch!='-' && (ch>'' || ch<''))ch=getchar();
if(ch=='-')ch=getchar(),y=;
while(ch>='' && ch<='')x=(x<<)+(x<<)+(ch^''),ch=getchar();
return y?x:-x;
} int main()
{
n=read();k=read();rp(i,,n)a[i]=read(),nw[i]=i,tmp[i]=i;
while(k)
{
if(k&){rp(i,,n)tmp[i]=nw[a[i]];rp(i,,n)nw[i]=tmp[i];}
rp(i,,n)tmp[i]=a[a[i]];rp(i,,n)a[i]=tmp[i];k>>=;
}
rp(i,,n)tmp[nw[i]]=i;
rp(i,,n)printf("%lld ",tmp[i]);
return ;
}

这是法二滴代码QwQ