<Pascal笔迹>>>快速幂
作者:A_Ender
[题目介绍]
求a的n次方除b的余数。
[样例输入,输出]
输入:1000000 100000 123231
输出:95734
[题目数据]
c<=b<=a<=31^2-1
{本题套路}
数据太大,会直接爆,普通的暴力完全不行。
{算法详解}
{1}这里使用到一个分治算法,将一个非常大的数据转化成一个个小数据。(乘号可以算是大数据与小数据的分界线)
如果n是基数,那么可以转换成[a^(n-1)*n]
如果n是偶数,那么又可以转换成[a^(n/2)*(a^2)]
{2}这是一个可以推理出来的公式。(乘号也可以算是大数据与小数据的分界线)
[a*b mod c=d]=[(a mod c)*(b mod c) mod c=d]
a和b可以看作是{1}的a^m和分化出来的数。
{3}基于{2}的公式,a和b可能会很大(当然不会有int64大),但用mod的话太慢了,所以这里判断偶数直接看个位是不是2的倍数就行了。
{算法演示}
3^13 [mod 4]
3^12*3
3^6*3*9
3^3*3*9
3^2*3*3*9
9*3*3*9
全部mod 4
1*3*3*1
总和[9]再mod 4
最后是1
<代码实现>
var
n,m,k,l:int64; //n,m,k分别为a,n,b l为下一次分化的数
function w(aa:int64):int64;//用字符串判断个位基偶
var
s:string;
begin
str(aa,s);
s:=s[length(s)]; //个位
if (s='0')or(s='2')or(s='4')or(s='6')or(s='8') then
exit(1)
else
exit(0);
end;
begin
l:=1;
read(n,m,k);
repeat
if w(m)=0 then //如果n是基数
begin
dec(m);
l:=l*(n mod k);
end
else
if w(m)=1 then //如果n是偶数
begin
m:=m div 2;
l:=l*(n*n mod k);
end;
l:=l mod k; //分化的也可能会大于b
until m<=2;
if m=2 then //再次判断(此部可以省略不看)
begin
l:=l*(n*n mod k);
l:=l mod k;
end;
if m=1 then
begin
l:=l*(n mod k);
l:=l mod k;
end;
write(l);
end.