关于快速幂
快速冪是個快速計算冪次的算法,原理很簡單:
a^b=a*a*a*a*a*......*a (b個a 相乘) 如果直接計算要做 b-1 次乘法。
可以利用冪運算的性質: a^b=(a^c)*(a^d)=a^(c+d) 其中b=c+d
如果把b平均分為兩份,每份的數量為c=d=b/2, a^c和a^d的值一樣,就可以重復利用。
這樣分一次就只要做 b/2-1+1=b/2次的乘法,若b為奇數,則要做b/2+1次乘法,于是乘法的次數就大大減少,
這樣重復分幾次后,原式的值就能很快地算出來。
用遞歸的代碼:
1 int QuickPow(int a,int b)
2 {
3 if (b==1) return a;
4 if (b&1) return QuickPow(a,b-1)*a; //b為奇數
5 return QuickPow(a,b/2);
6 }
非遞歸:
1 int QucikPow(int a,int b)
2 {
3 int ans=1;
4 while (b)
5 {
6 if (b&1) ans=ans*a;
7 b=b>>1;
8 a=a*a;
9 }
10 return ans;
11 }
注意事項:
1.用遞歸的方法會好理解點,但如果b很大的話遞歸會爆棧。
2. 函數返回值可能會溢出,如題目要求可利用模運算規則:(a*b)%m=(a%m*b%m)%m
3. 就算取模了,算法中有乘法操作的地方也還可能會溢出,這就要用快速冪的變式:
快速加法: a*b=a*(b/2)+a*(b/2)
(a+b)%m=(a%m+b%m)%m
這樣就不會溢出了。(還是在tyvj p2043 發現的,下面附上AC代碼)
1 #include <stdio.h>
2 unsigned long long p,m,n;
3 unsigned long long ans=1;
4 inline unsigned long long quickadd(unsigned long long a,unsigned long long m)
5 {
6 unsigned long long ans=0;
7 while (a)
8 {
9 if (a&1) ans=(ans+m)%p;
10 a=a>>1;
11 m=(m*2)%p;
12 }
13 return ans;
14 }
15 void quick(unsigned long long n)
16 {
17 while (n)
18 {
19 if (n&1) ans=(quickadd(ans,m))%p;
20 n=n>>1;
21 m=(quickadd(m,m))%p;
22 }
23 }
24
25 int main()
26 {
27 scanf("%I64d%I64d%I64d",&n,&m,&p);
28 ans=m%p;
29 m=m-1;
30 m=m%p;
31 quick(n-1);
32 printf("%I64d\n",ans);
33 }
總結
- 上一篇: 死了七次的男人
- 下一篇: C获取系统中CPU核数