快速幂(百科)
快速幂:
快速幂顾名思义,就是快速算某个数的多少次幂。其时间复杂度为 O(log2N), 与朴素的O(N)相比效率有了极大的提高。
以下以求a的b次方来介绍
1、快速幂 - 原理
把b转换成2进制数
该2进制数第i位的权为a^(2^(i-1))
例如
a^11=a^(2^0+2^1+2^3)
11的二进制是1 0 1 1
11 = 2^3*1 + 2^2*0 + 2^1*1 + 2^0*1
因此,我们将a^11转化为算a^(2^0)*a^(2^1)*a^(2^3)
2、实现
快速幂可以用位运算这个强大的工具实现
b and 1 //也就是取b的二进制最末位
b shr 1 //就是去掉b的二进制最末位
有了这个强大的工具,快速幂就好实现了!
var
a,b,n:int64;
function f(a,b,n:int64):int64;
var
t,y:int64;
begin
t:=1;y:=a;
while b<>0 do
begin
if (b and 1)=1 then t:=t*y mod n;
y:=y*y mod n; //这里用了一个很强大的技巧,y*y即求出了 a^(2^(i-1)) ←不知道这是什么的看原理
b:=b shr 1;
end;
exit(t);
end;
begin
read(a,b,n); // n是模
write(f(a,b,n));
end.
3、代码比较
常规求幂
int pow1( inta, int b ) {
int r = 1;
while( b-- )
r *= a;
return r;
}
快速求幂(一般)
int pow2( int a, int b ) {
int r = 1, base = a;
while( b != 0 ) {
if( b % 2 )
r *= base;
base *= base;
b /= 2;
}
return r;
}
快速求幂(位操作)
int pow3( int a, int b ) {
int r = 1, base = a;
while( b != 0 ) {
if( b & 1 )
r *= base;
base *= base;
b >>= 1;
}
return r;
}
实际代码应用:
Description:
兔子题
You must know the famous problem which the answer is Fibonacci Number: “A newly born pair of rabbits, one male, one female, are put in a field; rabbits are able to mate at the age of one month so that at the end of its second month a female can produce another pair of rabbits; rabbits never die and a mating pair always produces one new pair (one male, one female) every month from the second month on. How many pairs will there be after n months?”
Chino is interested in such problems. She thinks that the rabbits in this problem have 2 stages in their life: the first stage lasts one month that rabbits don’t produce rabbits in this stage; and the second stage lasts forever, each pair of rabbits produces one pair of rabbits every month in the second stage. Now she is considering a more complicated situation: the rabbits have m stages. In the first stage, they don’t produce rabbits. In the i-th stage, each pair of rabbits produces one pair of rabbits every i-1 month(s). The i-th stage lasts Ki month(s), and the rabbits die at the end of the last month of the m-th stage. The question is the same: how many pairs of rabbits will there be after n months?
As for detail, rabbits produce rabbits at the beginning of a month (different from the classic problem in the first paragraph), die at the end of a month, and we count the rabbits at the middle of a month. Also, the rabbits will produce rabbits at the first month of each stage (except the first stage)
Input Format
The input contains 2 lines:
There are 2 integers in the first line: m n, 0 < m < 6, 0 <= n <= 1e9
There are m integers in the second line: K1 K2 ... Km, 0 < Ki <= 40
Output Format
Only one integer: the answer mod 10007 (since the answer may be very large).
And don’t forget the ‘\n’.
Sample Input 1
4 5
1 2 4 8
Sample Output 1
29
Sample Input 2
4 1000000000
1 2 4 8
Sample Output 2
8435
Sample Input 3
3 7
1 2 4
Sample Output 3
103
样例3解释图:
Hint:
1) (a+b)%P = ((a%P)+(b%P))%P; (ab)%P = ((a%P)(b%P))%P
2) 直接推递推公式也会有困难,建议计算出转换矩阵,使得Ai+1=TAi
3) 在以上基础上推Tn计算TnA0,推Tn可用快速幂
standard answer:
#include <stdio.h> #include <string.h> #include <stdlib.h> #define P 10007 #define MAXm 5 int m, n, k[MAXm], s[MAXm]; int INT; int * INTP; int ** matNew(int k); void matFree(int **, int); int ** matPow(int **, int, int); int main() { scanf("%d%d", &m, &n); if (n > 0) { int i, j; for (i = 0; i < m; ++i) scanf("%d", k + i); s[0] = k[0]-1; for (i = 1; i < m; ++i) s[i] = s[i-1] + k[i]; int ** T = matNew(s[m-1]+1); for (i = 1; i < m; ++i) for (j = s[i-1]; j < s[i]; j += i) T[j][0] = 1; for (i = 1; i <= s[m-1]; ++i) T[i-1][i] = 1; int ** Tn = matPow(T, n, s[m-1]+1); int ans = 0; for (i = 0; i <= s[m-1]; ++i) ans = (ans + Tn[0][i]) % P; printf("%d\n", ans); matFree(Tn, s[m-1]+1); matFree(T, s[m-1]+1); } else { printf("1\n"); } return 0; } int ** matNew(int k) { int ** M = (int**)malloc(k * sizeof(INTP)); int i; for (i = 0; i < k; ++i) { M[i] = (int*)malloc(k * sizeof(INT)); memset(M[i], 0, k * sizeof(INT)); } return M; } void matFree(int ** M, int k) { int i; for (i = 0; i < k; ++i) free(M[i]); free(M); } int ** matPow(int ** T, int n, int k) { int ** ans = matNew(k); int i, j; if (n == 1) { for (i = 0; i < k; ++i) for (j = 0; j < k; ++j) ans[i][j] = T[i][j]; } else { int ** temp = matPow(T, n >> 1, k); int h; for (i = 0; i < k; ++i) for (j = 0; j < k; ++j) for (h = 0; h < k; ++h) ans[i][j] = (temp[i][h] * temp[h][j] + ans[i][j]) % P; matFree(temp, k); if (n & 1) { temp = ans; ans = matNew(k); for (i = 0; i < k; ++i) for (j = 0; j < k; ++j) for (h = 0; h < k; ++h) ans[i][j] = (temp[i][h] * T[h][j] + ans[i][j]) % P; matFree(temp, k); } } return ans; }