快速冪:復雜度為logn,比普通的n快了很多了.
原理 :
以求a的b次方來介紹:
首先把b轉換成二進制數
該二進制數第i位的權為 2^i - 1 .
比如 : 11的二進制是1011
11 = 23×1 + 22×0 + 21×1 + 2o×1
所以假設我們要求a^b,那么其實b是可以拆成二進制的,該二進制數第i位的權為2^(i-1),例如當b==11時
a^11=a^(2^0+2^1+2^3)
實現代碼如下:(位運算,簡單,簡潔)
long long pow(int a,int b) //位運算
{
long long r=1,base=a;
while(b)
{
if(b&1) r*=base; //r才是最終我們要的結果.
base *= base ; //一個中間轉移量.b每右移一次,base就多一個平方.
b >>= 1 ;
}
return r;
}
矩陣快速冪:
思想和快速冪差不多,只是這里是矩陣 , 而那個是數的差別.
所以原理和思想就不多說了 , 然后直接上代碼
while(b)
{
if(b&1) res *= A; //res是結果矩陣.
A *= A; //和快速冪一樣,每一次都是乘一個平方,因為最多也是差2的幾次方的問題.
b >>= 1 ;
}
難點在于如何構造A矩陣,只要構造出來了就簡單了.
給一道好題:點這(自己通過看下面那篇博客,自己推推,盡量不要搜題解)
不知道怎么建矩陣的請看這里,這個講的超級好點這里, 點這里, 看見了嗎, 點這里啊
思路就是很簡單:就是矩陣快速冪,主要是建好矩陣.
提供一個騷氣的寫法,就可以不用每一次寫矩陣形式,就是重載 * 號運算符. 代碼如下:
#define ll long long
#define db double
#define CLR(x) memset(x,0,sizeof(x))
const int ssize=10;
struct Ma{
db a[30][30];
void cc(){
CLR(a);
}
Ma operator * (const Ma &b) const { //重載 * 號運算符.
Ma tmp;
tmp.cc();
for(int i=0;i<ssize;i++){
for(int j=0;j<ssize;j++){
for(int k=0;k<ssize;k++){
if(b.a[k][j] == 0 || a[i][k] == 0) continue; //以后都把這個優化加上, 在有些卡數的題中會遇到.(如某個校賽F題)
tmp.a[i][j] += (a[i][k] * b.a[k][j]);
//tmp.a[i][j] %= mod;
}
}
}
return tmp;
}
}res,x; //有許多寫法,這只是其中一種,我認為好理解點的!
(怎么推要求那個矩陣的幾次方,就是用等比數列,an = a(n-1) * q ,然后看題目給的那一項從而推出是q的幾次方.)
好題的AC代碼:
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<iostream>
#define ll long long
using namespace std;
const ll mod = 2147493647;
struct Ma
{
ll a[10][10];
void cc()
{
memset(a,0,sizeof(a));
}
Ma operator * (const Ma & b) const {
Ma tmp;
tmp.cc();
for(int i=0;i<7;i++){
for(int j=0;j<7;j++){
for(int k=0;k<7;k++){
tmp.a[i][j] += (a[i][k] * b.a[k][j]);
tmp.a[i][j] %= mod;
}
}
}
return tmp;
}
}res,x;
void init()
{
res.cc();
for(int i=0;i<7;i++) //初始化為單位矩陣.
res.a[i][i] = 1 ;
x.cc(); // 初始化所推的那個矩陣.
x.a[0][0] = x.a[0][1] = 1;
x.a[1][0] = 2;
x.a[2][0] = x.a[2][2] = 1;
x.a[3][2] = 4 , x.a[3][3]=1;
x.a[4][2] = 6 , x.a[4][3] = 3 ,x.a[4][4] = 1 ;
x.a[5][2] = 4 , x.a[5][3] = 3 , x.a[5][4] = 2 , x.a[5][5] = 1 ;
x.a[6][2] = x.a[6][3] = x.a[6][4] = x.a[6][5] = x.a[6][6] = 1;
}
void qpow(ll n)
{
while(n)
{
if(n&1) res = res * x;
x = x*x ;
n >>= 1;
}
}
int main()
{
int t;
cin >> t;
while(t--){
ll N,m,n;
init();
cin >> N >> m >> n;
if(N < 3){
if(N == 1)
cout << m << endl;
else
cout << n << endl;
continue;
}
ll s[10] = {n,m,81,27,9,3,1}; //相當于第2項那個.這個就要自己想了.
qpow(N-2);
ll ans = 0 ;
for(int i=0;i<7;i++){
ans += ( res.a[i][0] * s[i] );
ans %= mod;
}
cout << ans << endl;
}
}
還有一道跟這道好題很相似的題(也是也一道好題!)鏈接在此