关于循环节的推导

365bet篮球比分直播 📅 2026-07-21 07:42:38 ✍️ admin 👁️ 5596 ❤️ 716
关于循环节的推导

关于循环节的推导

Lucaster_

·

2020-01-22 20:07:29

·

个人记录

题目传送门_P1965转圈游戏

首先奉上AC代码 (我知道你们是来看这个的咳咳):

#include

using namespace std;

int k,l,m,n,p,x;

inline int gcd(int a,int b)

{return (b==0)?a:gcd(b,a%b);}

inline int qpow(int a,int b)

{

int ans=1;

while(b)

{

if(b&1) ans=ans*a%p;

a=a*a%p;

b>>=1;

}

return ans%p;

}

int main()

{

cin>>n>>m>>k>>x;

p=n/gcd(n,m);

l=qpow(10,k);

cout<<(x+(m*l))%n;

return 0;

}

(有没有感觉好干净整洁咳咳)

前置芝士:gcd(辗转相除),快速幂

建议熟练掌握以上两点再食用本题解

Let's start:

读完题,不难看出这个问题是有循环节的,

我们设每经过p次换位可以换回原来的位置,p一定是可求的,而且换位一定是以p次为循环节循环的。

再一看题目中k的范围,(好家伙,这帮人要换10^10^9次位

显然是要找循环节的,而且似乎和gcd(n,m)有关

我写了几个例子(第一个数为n,第二个m):

10 3;8 6;24 18;45 27;47 5;

没错,我有意根据gcd构造的

发现循环节长度正是楼上大佬们写的那个式子:n/gcd(n,m)

(p.s.是我自己推的!我只是确认一下是不是这个式子才看的题解!)

有些人可能不太明白为什么,这里提供两种方法:

1.显然,手推一下我上面那五组数据(先求一下gcd,再模拟一下具体换位过程,发现次数就是那个式子)就看出来了……

2.(建议自己手画一下)我们设g=gcd(n,m),n=a*g,m=b*g;

首先,我们构造一个长l的区间,l=lcm(n,m),也就是l=a*b*g(lcm与gcd的相互转化)。

具体操作呢,画一条线段,记长度为l,再平均分成几份,每份长度为n,我们可以理解为每次换位不是转圈换,而是往下一段线段里换,(比如说例子中的n=10,m=3,0号第一次换到13,1号换到14,以此类推)那么在这条线段上一定能换到“初始位置”。(因为长为lcm(m,n)的线段一定能令n个人换m次换到初始位置)

用l除以m,就是循环节长度。

(在这条线段上感性理解一下)

根据题设,l=a*b*g,m=b*g,

那么循环节长度就是l/m=a=n/g=n/gcd(n,m)

证毕~

那么现在假设你已经知道循环节长度是怎么推的了,剩下的就很简单了——

我们还可以用这条线段理解,现在我们只需要移动10^k%p(循环节长度)次,也就是在线段上往后移m*(10^k%p)个单位长度

(加一句,如果不用快速幂的话最后一个点会T,亲身试验)

再加上初始位置x,再取个模

答案就是我程序里的最后cout后面那个式子啦!

最后return 0,完结撒花❀

希望我的思路和题解对您有帮助~

(觉得有帮助的留个赞再走呗~)

相关推荐

RabbitMQ(消息队列)安装部署
阴阳师雨女御魂要怎么配 雨女是命中和抵抗要多少
米哈游刘伟母校演讲实录:和蔡浩宇确实分手了,他干他的,我干我的