hdu3221 擴充套件尤拉定理(降冪大法)
阿新 • • 發佈:2019-01-07
題目連結:http://acm.hdu.edu.cn/showproblem.php?pid=3221
題解:首先很容易發現遞推公式fn=fn-1*fn-2;寫出前幾項a,b,a*b,a*b^2,a^2*b^3,a^3*b^5;易發現a,b的指數為斐波那契數列。但是當N大一點時,斐波那契數列便變得非常大。那麼此時得用擴充套件尤拉定理降冪。
a^b%p=a^(b%phi(p)+phi(p))%p b>=phi(p)(不要求a與p互質)
特別要主要使用條件, b>=phi(p)
接著用矩陣快速冪求斐波那契數列,再快速冪求答案即可。
題解:首先很容易發現遞推公式fn=fn-1*fn-2;寫出前幾項a,b,a*b,a*b^2,a^2*b^3,a^3*b^5;易發現a,b的指數為斐波那契數列。但是當N大一點時,斐波那契數列便變得非常大。那麼此時得用擴充套件尤拉定理降冪。
a^b%p=a^(b%phi(p)+phi(p))%p b>=phi(p)(不要求a與p互質)
特別要主要使用條件, b>=phi(p)
接著用矩陣快速冪求斐波那契數列,再快速冪求答案即可。
程式碼如下:
#include <bits/stdc++.h> #define ll long long using namespace std; const int maxn = 1000000 + 10; ll MOD = 1e9 + 7; ll a,b,n; ll phi[maxn]; struct Matrix{ ll n, m; ll mat[3][3]; Matrix(ll a = 0, ll b = 0):n(a),m(b) {memset(mat,0,sizeof(mat));} void init(ll a, ll b) {n = a;m = b;} Matrix operator *(const Matrix & x){ Matrix ans;ans.init(n,x.m); for(int i = 1;i <= n;i++){ for(int j = 1;j <= x.m;j++){ for(int k = 1;k <= m;k++){ ans.mat[i][j] += mat[i][k] * x.mat[k][j]; if(ans.mat[i][j] > phi[MOD]) ans.mat[i][j] = ans.mat[i][j] % phi[MOD] + phi[MOD]; } } } return ans; } }; Matrix q_pow(Matrix x, ll k){ Matrix ret;ret.init(2,2); ret.mat[1][1] = ret.mat[2][2] = 1; while(k > 0){ if(k & 1) ret = ret * x; x = x * x; k >>= 1; } return ret; } ll q_pow(ll x, ll k){ ll ret = 1; while(k > 0){ if(k & 1) ret = ret * x % MOD; x = x * x % MOD; k >>= 1; } return ret; } int primes[maxn],pcnt; void get_phi(int n){ memset(phi,0,sizeof(phi)); phi[1] = 1;int t = 0; for(int i = 2;i <= n;i++){ if(!phi[i]) { primes[++pcnt] = i; phi[i] = i - 1; } for(int j = 1;j <= pcnt;j++){ t = primes[j]; if(i * t > n) break; if(i % t == 0){ phi[i * t] = phi[i] * t; break; } else phi[i * t] = phi[i] * (t - 1); } } } int main() { get_phi(maxn - 10); int kase;scanf("%d",&kase); int T = 0; while(kase--){ printf("Case #%d: ",++T); scanf("%I64d%I64d%I64d%I64d",&a,&b,&MOD,&n); if(MOD == 1) {printf("0\n");continue;} if(n == 1) {printf("%I64d\n",a % MOD);continue;} if(n == 2) {printf("%I64d\n",b % MOD);continue;} Matrix tmp;tmp.init(2,2); tmp.mat[1][1] = 0;tmp.mat[1][2] = 1; tmp.mat[2][1] = 1;tmp.mat[2][2] = 1; Matrix p = Matrix(1,2); p.mat[1][1] = 1;p.mat[1][2] = 1; tmp = q_pow(tmp, n - 3); p = p * tmp; ll ans = 1; ans *= q_pow(a,p.mat[1][1]); ans *= q_pow(b,p.mat[1][2]); ans %= MOD; printf("%I64d\n",ans); } return 0; }