带模快速幂详解

2019-04-13 17:17发布

快速幂

用处

一个能快速求nk%pn^{k}\%p的算法,在数论题目里可以用来模拟多次重复的运算,是数论的基础算法。

模板题

【题目描述】

nk%pn^{k}\%p的值。

【输入格式】

一行,包含三个数n,k,pn,k,p

【输出格式】

一行,输出nk%pn^{k}\%p的值。

样例

样例输入

2 6 23

样例输出

18

样例说明

26=64,64%23=182^{6}=64,64\%23=18

数据范围与提示

对于全部数据,1n,k1015,1p1091le n,kle 10^{15},1 leq p leq 10^{9}

解析

这是一道基本的数论题,不用数论算法就会超时(简单来说,不用数论思想就是暴力模拟)。
暴力模拟的时间复杂度为O(k),O(k),kk最大可以取1015,10^{15},肯定会超时。
快速幂是一种时间复杂度为O(log2(k))O(log2(k))的算法,这代表kk甚至可以取到22×108(2200000000)LARGE2^{ ormalsize2 imes10^{8}}(2^{200000000})
可以说是无限了,C++中很难有这样的时间和内存够这种数运算了(FFT(FFT也做不到呀))
为什么说快速幂时间复杂度为为O(log2(k)),O(log2(k)),这因为它的算法模式。
利用22进制来分治,将运算次数缩小到二分的次数。
比如数据
2 29 657
n=2,k=29,p=657n=2,k=29,p=657
kk转化成22进制得11101,ans=111101,ans=1
每次nn都会平方并进行取模,然后将k÷2k div 2
因为nk=(n×2)k÷2n^{k}=(n imes2)^{k div 2}
但是CC语言中默认向下取整,所以5÷2=2,5div 2=2,但是还有个11该怎么办呢?
所以为什么转化为22进制,当k%2=1,k\%2=1,代表有一个11是多出来的,要先把这11aa先乘上。
具体代码实现如下 #include #include using namespace std; int n,k,p; int ksm(int a,int b,int inf) { int ans=1;a%=inf; while(b) { if(b&1/*b%2==1*/)ans=ans*a%inf; a=a*a%inf;b>>=1;/*b=b/2;*/ } return 0; } int main() { scanf("%d%d%d",&n,&k,&p); printf("%d ",ksm(n,k,p)); }

练习题 NOIP2013提高组day1【转圈游戏】

题目描述

nn个小伙伴((编号从00n1)n-1)围坐一圈玩游戏。按照顺时针方向给nn个位置编号,从00n1n-1。最初,第00号小伙伴在第00号位置,第11号小伙伴在第11号位置,……,依此类推。
游戏规则如下:每一轮第00号位置上的小伙伴顺时针走到第mm号位置,第11号位置小伙伴走到第m+1m+1号位置,……,依此类推,第nmn−m号位置上的小伙伴走到第00号位置,第nm+1n-m+1号位置上的小伙伴走到第11号位置,……,n1n-1号位置上的小伙伴顺时针走到第m1m-1号位置。
现在,一共进行了10k10^{k}轮,请问xx号小伙伴最后走到了第几号位置。

输入格式

输入共11行,包含44个整数n,m,k,x,n,m,k,x,每两个整数之间用一个空格隔开。

输出格式

输出共11行,包含11个整数,表示10k10^{k}轮后xx号小伙伴所在的位置编号。

样例

样例输入1

10 3 4 5

样例输出1

5

数据范围与提示

对于30%30\%的数据,0<k<7,0 < k < 7;
对于80%80\%的数据,0<k<107;,0 < k < 10^{7};
对于100%100\%的数据,1<n<106,0<m<n,1xn,0<k<109,1 < n < 10^{6},0 < m < n,1 leq x leq n,0 < k < 10^9。