帶模快速冪詳解


CSDN的博客

用處

一個能快速求\(n^{k}\%p\)的算法,在數論題目里可以用來模擬多次重復的運算,是數論的基礎算法。

模板題

【題目描述】

\(n^{k}\%p\)的值。

【輸入格式】

一行,包含三個數\(n,k,p\)

【輸出格式】

一行,輸出\(n^{k}\%p\)的值。

樣例

樣例輸入

2 6 23

樣例輸出

18

樣例說明

\(2^{6}=64,64\%23=18\)

數據范圍與提示

對於全部數據,\(1\le n,k\le 10^{15},1 \leq p \leq 10^{9}\)

解析

這是一道基本的數論題,不用數論算法就會超時(簡單來說,不用數論思想就是暴力模擬)。
暴力模擬的時間復雜度為\(O(k),\)\(k\)最大可以取\(10^{15},\)肯定會超時。
快速冪是一種時間復雜度為\(O(log2(k))\)的算法,這代表\(k\)甚至可以取到\(\LARGE2^{\normalsize2\times10^{8}}(2^{200000000})\)
可以說是無限了,C++中很難有這樣的時間和內存夠這種數運算了\((FFT\)也做不到呀\()\)
為什么說快速冪時間復雜度為為\(O(log2(k)),\)這因為它的算法模式。
利用\(2\)進制來分治,將運算次數縮小到二分的次數。
比如數據

2 29 657

\(n=2,k=29,p=657\)
\(k\)轉化成\(2\)進制得\(11101,ans=1\)
每次\(n\)都會平方並進行取模,然后將\(k \div 2\)
因為\(n^{k}=(n\times2)^{k \div 2}\)
但是\(C\)語言中默認向下取整,所以\(5\div 2=2,\)但是還有個\(1\)該怎么辦呢?
所以為什么轉化為\(2\)進制,當\(k\%2=1,\)代表有一個\(1\)是多出來的,要先把這\(1\)\(a\)先乘上。
具體代碼實現如下

#include<cstdio>
#include<cstring>
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\n",ksm(n,k,p));
}

練習題 NOIP2013提高組day1【轉圈游戲】

題目描述

\(n\)個小伙伴\((\)編號從\(0\)\(n-1)\)圍坐一圈玩游戲。按照順時針方向給\(n\)個位置編號,從\(0\)\(n-1\)。最初,第\(0\)號小伙伴在第\(0\)號位置,第\(1\)號小伙伴在第\(1\)號位置\(,……,\)依此類推。
游戲規則如下:每一輪第\(0\)號位置上的小伙伴順時針走到第\(m\)號位置,第\(1\)號位置小伙伴走到第\(m+1\)號位置\(,……,\)依此類推,第\(n−m\)號位置上的小伙伴走到第\(0\)號位置,第\(n-m+1\)號位置上的小伙伴走到第\(1\)號位置\(,……,\)\(n-1\)號位置上的小伙伴順時針走到第\(m-1\)號位置。
現在,一共進行了\(10^{k}\)輪,請問\(x\)號小伙伴最后走到了第幾號位置。

輸入格式

輸入共\(1\)行,包含\(4\)個整數\(n,m,k,x,\)每兩個整數之間用一個空格隔開。

輸出格式

輸出共\(1\)行,包含\(1\)個整數,表示\(10^{k}\)輪后\(x\)號小伙伴所在的位置編號。

樣例

樣例輸入1

10 3 4 5

樣例輸出1

5

數據范圍與提示

對於\(30\%\)的數據\(,0 < k < 7;\)
對於\(80\%\)的數據\(,0 < k < 10^{7};\)
對於\(100\%\)的數據\(,1 < n < 10^{6},0 < m < n,1 \leq x \leq n,0 < k < 10^9。\)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM