您的位置:首页 > 其它

hdu3221 扩展欧拉定理(降幂大法)

2017-08-16 16:58 281 查看
题目链接: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)

接着用矩阵快速幂求斐波那契数列,再快速幂求答案即可。
代码如下:

#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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  ACM