(牛客第一场)J.u's的影响力(矩阵快速幂,费马小定理)
第一天的影响力为,第二天的影响力为
,从第三天开始,每一天的影响力为前两天的影响力的乘积再乘以
的
次方。用数学语言描述:
。输出第n天的影响力,对1e9+7取模。
由于,所以用快速幂。
先推几个公式,找规律:
从第三项开始x的幂次为1,1,2,3,5...是斐波那契数列
的幂次为
是斐波那契数列
的幂次为
不是斐波那契数列,但为前两项之和+1
同时还需用到一个数论的结论:费马小定理。
费马小定理:为素数,对于任意整数
都有
。
若无法被
整除,则有
。
根据费马小定理,我们可以通过矩阵快速幂求得逆元,因为由上式有,不过跟这题没关系。
矩阵快速幂求斐波那契数列
由于数据范围很大,如果用递推求斐波那契数列显然会超时。
模板
typedef vector<int> vec;
typedef vector<vector<int>> mat;
typedef long long ll;
const ll mod=1e9+7;
// 首先求出两个矩阵乘积
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])%mod;
return C;
}
//算快速幂
mat poww(mat A,ll n){
mat B(A.size(),vec(A.size()));
for(int i=0;i<A.size();i++)
B[i][i]=1;
//相当于朴素快速幂里面res=1; 将B矩阵对角线元素初始化为1
while(n>0){
if(n&1) B=mul(B,A);
A=mul(A,A);
n>>=1;
}
return B;
}
void fib(int n){
mat A(2,vec(2));
A[0][0]=A[0][1]=A[1][0]=1;
A[1][1]=0;
A=poww(A,n-1);
printf("%d",A[0][0]);
//A[0][0] 对应斐波那契数列的第 n 项
} 题解代码
#include <iostream>
#include <cstdio>
#include <vector>
using namespace std;
typedef long long ll;
typedef vector<ll> vec;
typedef vector<vector<ll>> mat;
const ll mod=1e9+6; //费马小定理,用的模数
const ll mod2=1e9+7; //答案所用模数
// 首先求出两个矩阵乘积
mat mul(mat &A,mat &B){ //用模数1,矩阵快速幂算的是x,y,a^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]%mod)%mod;
return C;
}
//算快速幂
mat poww(mat A,ll n){
mat B(A.size(),vec(A.size()));
for(int i=0;i<A.size();i++)
B[i][i]=1;
//相当于朴素快速幂里面res=1; 将B矩阵对角线元素初始化为1
while(n>0){
if(n&1) B=mul(B,A);
A=mul(A,A);
n>>=1;
}
return B;
}
ll poww(ll a,ll n){ //用模数2,算出最终答案
// 底数为0时,直接返回0, 否则会卡10% 的数据
if(a==0) return 0;
ll res=1;
while(n>0){
if(n&1) res=res*a%mod2;
a=a*a%mod2;
n>>=1;
}
return res;
}
int main(){
mat A(2,vec(2));
A[0][0]=A[0][1]=A[1][0]=1;
A[1][1]=0;
//矩阵1
/*
1 1
1 0
用来算斐波那契数,也就是x,y的模数
*/
mat B(3,vec(3));
B={{1,1,1},{1,0,0},{0,0,1}};
//矩阵2
/*
1 1 1
1 0 0
0 0 1
用来算a^b的幂次
*/
ll n,x,y,a,b;
cin>>n>>x>>y>>a>>b;
x%=mod2;y%=mod2;
a%=mod2; //分别对mod2取模
if(n==1){
printf("%lld\n",x); //输出前两项
return 0;
}
if(n==2){
printf("%lld\n",y);
return 0;
}
if(a==0||x==0||y==0){ //由前面费马小定理幂次同余模p的条件,a,x,y能直接被mod2整除,输出0
printf("0\n");
return 0;
}
a=poww(a,b);
A=poww(A,n-2);
B=poww(B,n-2);
ll p=A[0][0], q=A[1][0], r=(B[1][0]+B[1][2])%mod;//分别对应y 的幂次,x的幂次,a^b的幂次
ll ans=(poww(x,q)*poww(y,p)%mod2*poww(a,r))%mod2; //快速幂求答案
printf("%lld\n",ans%mod2);
return 0;
} 
京公网安备 11010502036488号