小爱密码
序号:#137 难度:困难 时间限制:1000ms 内存限制:80M
描述
小爱同学有一个智能密码锁。锁上有九位数字,小爱同学每次会给A,B,C,D,mod,n六个正整数。 题目是这样的:
F(1) = A, F(2) = B
F(n) = F(n-1)*F(n-2)* C^D(n>2)
现在小爱同学想计算出 G(n) 的值(G(n)为F(n)的前n项积),并用该值作为密码锁的密码。
由于结果过大,所以答案 G(n)%mod
输入
多组数据。每组包含 6 个整数,分别代表 A, B, C, D, mod, n. (1<=A,B,C,D,mod,n<=1000000000);数据组数不超过 2000.
输出
输出 G(n)%mod 的值。
答案保留 9 位有效数字,不足则补 0.
输入样例
2 2 2 2 1000 3 7 9 3 4 6 5
复制样例
输出样例
000000064 000000003
题意:求F(n)的前n项积%mod,即题目里说的G(n)%mod
题解:写出几项后可以发现规律,乘积可以变成幂的指数相加形式,即最后可以变成A^x*B^b*(C^D)^z,主要是求x,y,z的过程,这样说太抽象了,看过程:
可以看出是一个求菲波那切数列的过程,不过数会很大,需要用到,欧拉降幂,即: A^X%mod=A^(X%get_euler(mod)+get_euler(mod))%mod,加mod是为了变成正的~~
上代码:
#include <iostream>
#include <cstring>
using namespace std;
typedef long long ll;
struct hh{
ll a[4][4];
}x;
ll get_euler(ll n){//欧拉函数
ll res=n,a=n;
for (ll i = 2; i*i <= a;i++){
if(a%i==0){
res=res/i*(i-1);
while(a%i==0) a=a/i;
}
}
if(a>1) res=res/a*(a-1);
return res;
}
hh mul(hh a,hh b,ll c){//矩阵快速幂,用来求指数,即菲波那切数列
hh w;
memset(w.a,0,sizeof(w.a));//初始化别忘记
for (int i = 0; i < 2;i++){
for (int j = 0; j < 2; j++){
for (int k = 0; k < 2;k++){
w.a[i][j]=(w.a[i][j]+a.a[i][k]*b.a[k][j]%c)%c;
}
}
}
return w;
}
hh quick1(hh a,ll b,ll c){//矩阵快速幂,用来求指数,即菲波那切数列
hh ans;
memset(ans.a,0,sizeof(ans.a));//初始化别忘记
for (int i = 0; i < 2; i++){
ans.a[i][i]=1;
}
while(b){
if(b&1) ans=mul(ans,a,c);
b>>=1;
a=mul(a,a,c);
}
return ans;
}
ll quick2(ll a,ll b,ll c){//数的快速幂,用来求C^D
ll ans=1;
a=a%c;
while(b){
if(b&1) ans=(ans*a)%c;
b>>=1;
a=(a*a)%c;
}
return ans%c;
}
int main(){
ll a,b,c,d,mod,n,modd;
while(cin >> a >> b >> c >> d >> mod >> n){
modd=get_euler(mod);
x.a[0][0]=1;x.a[0][1]=1;
x.a[1][0]=1;x.a[1][1]=0;//初始化别忘记
hh w1=quick1(x,n,modd);//记住modd和mod别用错了,求a的指数
hh w2=quick1(x,n+1,modd);//记住modd和mod别用错了,求b的指数
ll aaa=w1.a[1][0]+modd;//记住modd和mod别用错了,求a的指数
ll bbb=w2.a[1][0]-1+modd;//记住modd和mod别用错了,求b的指数
ll ccc=aaa+bbb-n%modd+modd;//记住modd和mod别用错了,n也要模一下,不然很难变成正的,求c^d的指数
c=quick2(c,d%modd+modd,mod);//记住modd和mod别用错了,求c^d
ll anss=(quick2(a,aaa,mod)*quick2(b,bbb,mod)%mod*quick2(c,ccc,mod))%mod;//记住modd和mod别用错了,求结果~~
printf("%09lld\n",anss);//注意格式
}
return 0;
}