题目链接;
HDU 3221 Brute-force Algorithm
题意:
根据递归可以得到 f[1]=a,f[2]=b,f[n]=f[n?1]?f[n?2](n≥3) ,给出 a,b,p,n 求 f[n]%p的值。
数据范围: 1≤n≤1000000000,1≤P≤1000000,0≤a,b<1000000.
分析:
设菲波那切数列第 n 项为
f[n]=ag(n?1)?bg(n) %p (n≥3)
但是考虑到指数 g(n) 会很大,我们需要降幂。
指数降幂公式:
Ax % p=Ax%?(p)+?(p) % p (x≥?(p),?(p)是p的欧拉函数值)
所以用矩阵快速幂求菲波那切数列时的取模数是 ?(p) 而不是 p 。
下面的代码用
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <algorithm>
#include <climits>
#include <cmath>
#include <ctime>
#include <cassert>
#include <bitset>
#define IOS ios_base::sync_with_stdio(0); cin.tie(0);
using namespace std;
typedef long long ll;
const int SIZE = 10;
const int MAX_N = 1000010;bitset<MAX_N> bs;
int prime_cnt, prime[MAX_N], phi[MAX_N];struct Matrix {int row, col;ll data[SIZE][SIZE];Matrix () {}Matrix (int _row, int _col): row(_row), col(_col) {}
};void GetPhi()
{bs.set();prime_cnt = 0;phi[1] = 1;for(int i = 2; i < MAX_N; ++i) {if(bs[i] == 1) {prime[prime_cnt++] = i;phi[i] = i - 1;}for(int j = 0; j < prime_cnt && i * prime[j] < MAX_N; ++j) {bs[i * prime[j]] = 0;if(i % prime[j]) {phi[i * prime[j]] = (prime[j] - 1) * phi[i];}else {phi[i * prime[j]] = prime[j] * phi[i];break;}}}
}Matrix matrix_mul(Matrix a, Matrix b, ll p)
{Matrix res;memset(res.data, 0, sizeof(res.data));res.row = a.row, res.col = b.col;for(int i = 1; i <= res.row; ++i) {for(int j = 1; j <= res.col; ++j) {for(int k = 1; k <= a.col; ++k) {res.data[i][j] += a.data[i][k] * b.data[k][j];if(res.data[i][j] > p) res.data[i][j] = (res.data[i][j] % p + p);}}}return res;
}Matrix matrix_quick_pow(Matrix a, ll b, ll p)
{Matrix res, tmp = a;memset(res.data, 0, sizeof(res));res.row = res.col = a.row;for(int i = 1; i <= res.row; ++i) { res.data[i][i] = 1; }while(b) {if(b & 1) res = matrix_mul(res, tmp, p);tmp = matrix_mul(tmp, tmp, p);b >>= 1;}return res;
}ll quick_pow(ll a, ll b, ll c)
{ll res = 1, tmp = a % c;while(b) {if(b & 1) res = res * tmp % c;tmp = tmp * tmp % c;b >>= 1;}return res;
}int main()
{GetPhi();int T, cases = 0;ll a, b, p, n;scanf("%d", &T); while(T--) {scanf("%lld%lld%lld%lld", &a, &b, &p, &n);if(n == 1) {printf("Case #%d: %lld\n", ++cases, a % p);continue;} else if(n == 2) {printf("Case #%d: %lld\n", ++cases, b % p);continue;} else if(n == 3) {printf("Case #%d: %lld\n", ++cases, a * b % p);continue;} else if(a == 0 || b == 0 || p == 1) {printf("Case #%d: %d\n", ++cases, 0);continue;}Matrix res, tmp;tmp.row = tmp.col = 2;tmp.data[1][1] = 0, tmp.data[1][2] = 1;tmp.data[2][1] = 1, tmp.data[2][2] = 1;res.row = 2, res.col = 1;res.data[1][1] = 0, res.data[2][1] = 1;tmp = matrix_quick_pow(tmp, n - 2, phi[p]);res = matrix_mul(tmp, res, phi[p]);ll ans = quick_pow(a, res.data[1][1], p);ans = ans * quick_pow(b, res.data[2][1], p) % p;printf("Case #%d: %lld\n", ++cases, ans);}return 0;
}