// 快速幂:
//顾名思义,快速幂就是快速算底数的n次幂。其时间复杂度为 O(log₂N),
//与朴素的O(N)相比效率有了极大的提高
#include <cstdio>
#define MOD 1000000007
int Pow(int a,int n) // recursive solution
{
if(n == 0)
return 1;
int temp = Pow(a,n >> 1);
temp = temp * temp % MOD;
if(n & 1)
temp = temp * a % MOD;
return temp;
}
int Foo(int a,int n)
{
int temp = 1;
int y = a;
while(n)
{
if(n&1)
temp = temp * y % MOD;// 利用二进制的思想n^(10) = n^(B1010)
// 出现n&1 此时y表示n^(2) n^(2) * n^(8) = n^(10)
y = y * y % MOD;
n = n >> 1;
}
return temp;
}
int main()
{
int a,b;
while(1)
{
scanf("%d%d",&a,&b);
printf("%d\n",Foo(a,b));
printf("%d\n",Pow(a,b));
}
return 0;
}
利用快速幂的思想求矩阵M的N的次方
题目描述:https://hihocoder.com/problemset/problem/1504?sid=1074922
在8x8的国际象棋棋盘上给定一只骑士(俗称“马”)棋子的位置(R, C),小Hi想知道从(R, C)开始移动N步一共有多少种不同的走法。
输入
第一行包含三个整数,N,R和C。
对于40%的数据, 1 <= N <= 1000000
对于100%的数据, 1 <= N <= 1000000000 1 <= R, C <= 8
输出
从(R, C)开始走N步有多少种不同的走法。由于答案可能非常大,你只需要输出答案模1000000007的余数。
样例输入
2 1 1
样例输出
12
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
#define MOD 1000000007
int Pow(int r,int c,int n)
{
//Map to set from x to y
const int buff[8][2] = {
{-1,+2},{-1,-2},{+1,+2},{+1,-2},
{+2,-1},{-2,-1},{+2,+1},{-2,+1}
};
long long Map[64][64] = {0};
long long Result[64] = {0};
for(int i = 0;i < 8;i ++)
for(int j = 0;j < 8;j ++)
{
for(int k = 0;k < 8;k ++)
{
int x = i + buff[k][0];
int y = j + buff[k][1];
if(x >= 0 && x < 8 && y >= 0 && y < 8)
{
Map[i * 8 + j][x * 8 + y] = 1;
}
}
}
// Map ^ n then sum the array
for(int i = 0;i < 64;i ++)
Result[i] = 1;
while(n)
{
if(n & 1)
{
long long t[64] = {0};
for(int i = 0;i < 64;i ++)
for(int j = 0;j < 64;j ++)
{
t[i] = t[i] + Map[i][j] * Result[j] % MOD;
}
for(int i = 0;i < 64;i ++)
Result[i] = t[i] % MOD;
}
int temp[64][64] = {0};
for(int i = 0;i < 64;i ++)
for(int j = 0;j < 64;j ++)
{
long long t = 0;
for(int k = 0;k < 64;k ++)
t += Map[i][k] * Map[k][j] % MOD;
temp[i][j] = t % MOD;
}
for(int i = 0;i < 64;i ++)
for(int j = 0;j < 64;j ++)
Map[i][j] = temp[i][j];
n = n >> 1;
}
return Result[r * 8 + c];
}
int main()
{
int N,R,C;
scanf("%d%d%d",&N,&R,&C);
R --,C --;
printf("%d\n",Pow(R,C,N));
return 0;
}
DFS计数问题,题目描述:https://hihocoder.com/problemset/problem/1560?sid=1156184
#include <cstdio>
#include <algorithm>
#include <iostream>
#include <cstring>
using namespace std;
#define MOD 1000000007
long long aans = 0;
long long A[10][10] = {0};
long long AA[10][10] = {0};
long long min_(long long n,long long m)
{
return n < m ? n : m;
}
void power(long long n)
{
while(n)
{
if(n&1)
{
long long tmpp[10][10] = {0};
for(int i = 0;i < 10;i ++)
for(int j = 0;j < 10;j ++)
for(int k = 0;k < 10;k ++)
tmpp[i][j] += A[i][k] * AA[k][j] % MOD;
for(int i = 0;i <= 9;i ++)
for(int j = 0;j <= 9;j ++)
A[i][j] = tmpp[i][j] % MOD;
}
long long tmp[10][10] = {0};
for(int i = 0;i < 10;i ++)
for(int j = 0;j < 10;j ++)
{
long long t = 0;
for(int k = 0;k < 10;k ++)
t += AA[i][k] * AA[k][j] % MOD;
tmp[i][j] = t % MOD;
}
for(int i = 0;i < 10;i ++)
for(int j = 0;j < 10;j ++)
AA[i][j] = tmp[i][j];
n = n >> 1;
}
return;
}
int main()
{
long long n,m;
cin >> n >> m;
for(int i = 0;i <= 9;i ++)
{
for(int j = 0;j <= 9;j ++)
{
if(i == 0)
A[i][j] = 0;
else if(j == 0)
{
if(i == 0)
A[i][j] = 0;
else if(i <= min_(9,m))
A[i][j] = 1;
}
else
{
if(i*j <= m)
A[i][j] = 1;
}
}
}
for(int i = 0;i <= 9;i ++)
{
for(int j = 0;j <= 9;j ++)
{
if(i == 0)
{
if(j <= min_(9,m))
AA[i][j] = 1;
}
else if(j == 0)
{
if(i <= min_(9,m))
AA[i][j] = 1;
}
else
{
if(i*j <= m)
AA[i][j] = 1;
}
}
}
if(n == 1)
cout << min_(9,m);
else if(n == 2)
{
for(int i = 0;i <= 9;i ++)
for(int j = 0;j <= 9;j ++)
aans = aans + A[i][j] % MOD;
cout << aans % MOD << endl;
}
else{
power(n-2);
for(int i = 0;i <= 9;i ++)
for(int j = 0;j <= 9;j ++)
aans = aans + A[i][j] % MOD;
cout << aans % MOD << endl;
}
return 0;
}