您的位置:首页 > 编程语言 > Go语言

HDU 3221 Brute-force Algorithm

2015-01-30 21:29 190 查看
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3221

思路:

稍微开个脑洞想想,就能发现递推式是f(n)=f(n-1)*f(n-2),再想想就能想到可通过先计算a用了多少次,b用了多少次来计算,最后套一个快速幂来计算f(n),在计算a用了多少次的时候又可以发现,a的次数其实是一个斐波那契数,但是在计算a的次数的时候会发现这个次数会爆long long并且不能简单的来用P进行取模,怎么办呢? 怎么办呢? 想了好久后来才知道这个地方有一个公式:

(a^b)%mo=(a^(b%phi[mo]+phi[mo]))%mo b>=phi[mo]

用这个公式在矩阵快速幂的时候对b进行取模就好(ps:不是直接对phi[mo]取模~~~)

code:

#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>
#include <cmath>

using namespace std;

typedef long long LL;

typedef vector<LL> vec;
typedef vector<vec> mat;

LL mo,mod;

LL mod_pow(LL x,LL n)
{
LL res=1;
while(n>0){
if(n&1) res=res*x%mo;
x=x*x%mo;
n>>=1;
}
return res;
}

mat mul(mat &A,mat &B)
{
mat C(A.size(),vec(B[0].size()));
for(int i=0;i<A.size();i++){
for(int k=0;k<B.size();k++){
for(int j=0;j<B[0].size();j++){
C[i][j]=C[i][j]+A[i][k]*B[k][j];
if(C[i][j]>mod) C[i][j]=C[i][j]%mod+mod;
}
}
}
return C;
}

mat pow(mat A,LL n)
{
mat B(A.size(),vec(A.size()));
for(int i=0;i<A.size();i++) B[i][i]=1;
while(n>0){
if(n&1) B=mul(B,A);
A=mul(A,A);
n>>=1;
}
return B;
}

LL euler(LL x)
{
LL i, res = x;
for (i = 2; i*i <= x; i++)
{
if (x%i == 0)
{
res = res / i*(i - 1);
while (x%i == 0)
x /= i;
}
}
if (x > 1)
res = res / x*(x - 1);
return res;
}

int main()
{
LL a,b,n,m1,m2,res;
int T;
scanf("%d",&T);
for(int kk=1;kk<=T;kk++){
scanf("%I64d%I64d%I64d%I64d",&a,&b,&mo,&n);
printf("Case #%d: ",kk);
//if(mo==1) printf("0\n");
//else if(n==1) printf("%I64d\n",a%mo);
//else if(n==2) printf("%I64d\n",b%mo);
//else{
mod=euler(mo);
mat A(2,vec(2));
A[0][0]=A[0][1]=1;
A[1][0]=1;A[1][1]=0;
A=pow(A,n-1);
m1=A[1][1];
if(m1>=mod) m1=m1%mod+mod;
m2=A[1][0];
//cout<<m1<<" "<<m2<<endl;
if(m2>=mod) m2=m2%mod+mod;
res=(mod_pow(a,m1)*mod_pow(b,m2))%mo;
printf("%I64d\n",res);
// }
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: