原题链接
P1226
题目类型:
普
及
−
{\color{orange} 普及-}
普及−
AC记录:Accepted
题目大意
给你三个数
a
,
b
,
p
a,b,p
a,b,p,求出
a
b
%
p
a^b\ \%\ p
ab % p的结果。
输出格式为a^b mod p=s
,其中
a
,
b
,
p
a,b,p
a,b,p如上,
s
s
s为计算的结果。
S
a
m
p
l
e
\mathbf{Sample}
Sample
I
n
p
u
t
\mathbf{Input}
Input
2 10 9
S a m p l e \mathbf{Sample} Sample O u t p u t \mathbf{Output} Output
2^10 mod 9=7
H
i
n
t
&
E
x
p
l
a
i
n
\mathbf{Hint\&Explain}
Hint&Explain
2
10
=
1024
,
1024
m
o
d
9
=
7
2^{10}=1024,1024\mod 9=7
210=1024,1024mod9=7
数据范围
对于 100 % 100\% 100%的数据,保证 0 ≤ a , b < 2 31 , a + b > 0 , 2 ≤ p < 2 31 0\le a,b<2^{31},a+b>0,2\le p <2^{31} 0≤a,b<231,a+b>0,2≤p<231。
解题思路
看看数据,直接做肯定会溢出,正确的做法是用二进制来做。
我们可以把
b
b
b化为二进制,将原本的
a
b
a^b
ab看成若干个互不相同的
a
a
a的
2
k
2^k
2k次方相乘得到的结果,如:
(
10
)
10
=
(
1010
)
2
a
10
=
(
1
×
a
8
)
×
(
0
×
a
4
)
×
(
1
×
a
2
)
×
(
0
×
a
1
)
=
a
8
×
a
2
\ \ \ \ \ \ \ \ \ \ \ \ (10)_{10}=(1010)_2\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \\ \ \\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ a^{10}= ( 1\times a^8 ) \times ( 0\times a^4 ) \times ( 1\times a^2 ) \times ( 0\times a^1 ) \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \\ =a^8 \times a^2 \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \
(10)10=(1010)2 a10=(1×a8)×(0×a4)×(1×a2)×(0×a1) =a8×a2
由于每一笔运算的结果都有一个 p p p在限制运算结果的上限,所以在这里的每一笔运算都不会溢出。
但这里还有一个问题,
b
b
b的最大值为
2
31
−
1
2^{31}-1
231−1,如果手动存储
2
k
2^k
2k得到的结果,再运算
a
2
k
a^{2^k}
a2k的值还是拿不到满分,因为最大
a
k
a^k
ak的值为
a
2
30
a^{2^{30}}
a230,需要运行
2
30
2^{30}
230次,这个时间肯定会超时,所以这里有一个小技巧:
我们已知:
a
b
×
a
c
=
a
b
+
c
那么
(
a
2
i
)
2
=
(
a
2
i
)
×
(
a
2
i
)
=
a
2
i
+
2
i
=
a
2
i
×
2
=
a
2
i
+
1
\text{我们已知:}a^b \times a^c=a^{b+c} \\ \text{那么}\left( a^{2^i} \right)^2=\left( a^{2^i} \right) \times \left( a^{2^i} \right)=a^{2^i+2^i}=a^{2^i\times2}=a^{2^{i+1}}
我们已知:ab×ac=ab+c那么(a2i)2=(a2i)×(a2i)=a2i+2i=a2i×2=a2i+1
由上面的公式,我们可以只存储
a
a
a的值,当进入到下一位的时候,我们就将
a
a
a设为
a
×
a
%
p
a\times a \ \% \ p
a×a % p,这样就可以解决了。
最后,祝大家早日
上代码
#include<iostream>
using namespace std;
typedef unsigned long long ull;
typedef long long ll;
void POWER_AND_PRINT(ull a,ull b,ull p)
{
ull initA=a,initB=b;
ull ans=1%p;
a%=p;
for(; b; b>>=1)
{
if(b&1) ans=(ull)ans*a%p;
a=(ull)a*a%p;
}
cout<<initA<<"^"<<initB<<" mod "<<p<<"="<<ans<<endl;
}
int main()
{
ull n,m,k;
cin>>n>>m>>k;
POWER_AND_PRINT(n,m,k);
return 0;
}
完美切题 ∼ \sim ∼