PYXFIB
题解
一看就是一道的数论题。谁都知道
至于斐波拉契的做法应该都知道,用一个的矩阵就可以处理了。
关键是如何解决前面那个组合数呢?
通过这个式子,很容易想到二项式展开定理。
针对矩阵肯定也是成立的,,(为单位矩阵)。
不过我们还需判断,这样就与原式等价了。
我们现在的目的是构造一个数组使得满足。
g为p的原根,w为p的单位根即。那么当且仅当在模p的意义下。所以只有在时为k,其他时候都为0。
于是原式等价于。
我们设
于是。
这就很容易用矩阵快速幂求出了。
源码
#include<cstdio>
#include<cmath>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<queue>
#include<vector>
#include<map>
using namespace std;
typedef long long LL;
#define int LL
#define gc() getchar()
template<typename _T>
inline void read(_T &x){
_T f=1;x=0;char s=gc();
while(s>'9'||s<'0'){if(s=='-')f=-1;s=gc();}
while(s>='0'&&s<='9'){x=(x<<3)+(x<<1)+(s^48);s=gc();}
x*=f;
}
int cnt,n,k,p,y[1000005];
int pow(int a,int s){
int t=1;a%=p;
while(s){
if(s&1)t=a*t%p;
a=a*a%p;s>>=1;
}
return t;
}
struct matrix{
int n,m,c[20][20];
matrix(){n=m=0;memset(c,0,sizeof(c));}
matrix operator * (const matrix& a){
matrix r;r.n=n;r.m=a.m;
for(int i=1;i<=r.n;i++)
for(int j=1;j<=r.m;j++)
for(int k=1;k<=m;k++)
(r.c[i][j]+=(c[i][k]*a.c[k][j]%p))%=p;
return r;
}
matrix operator + (const matrix& a){
matrix r;r.n=n;r.m=m;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
r.c[i][j]=(a.c[i][j]+c[i][j])%p;
return r;
}
}A;
matrix qkpow(matrix a,LL s){
matrix res;res.n=res.m=a.n;
for(int i=1;i<=res.m;i++) res.c[i][i]=1;
while(s){
if(s&1)res=res*a;
a=a*a;s/=2;
}
return res;
}
int calc(int x){
matrix ans;ans.n=ans.m=2;
ans.c[1][1]=ans.c[2][2]=x;ans.c[1][2]=ans.c[2][1]=0;
ans=ans+A;ans=qkpow(ans,n);
int nix=pow(pow(x,n),p-2);
for(int i=1;i<=ans.n;i++)
for(int j=1;j<=ans.m;j++)
ans.c[i][j]=ans.c[i][j]*nix%p;
return ans.c[1][1];
}
bool judge(int x){
for(int i=1;i<=cnt;i++)
if(pow(x,y[i])%p==1)
return false;
return true;
}
void get_yinshu(int x){
for(int i=2;i<=sqrt(x);i++){
if(x%i)continue;
y[++cnt]=i;
if(x/i>i)y[++cnt]=x/i;
}
}
int get_w(){
get_yinshu(p-1);int g;
for(g=2;g;g++)if(judge(g))break;
return pow(g,(p-1)/k);
}
signed main(){
int t;read(t);
while(t--){
cnt=0;A.n=A.m=2;
A.c[1][1]=A.c[1][2]=A.c[2][1]=1;A.c[2][2]=0;
read(n);read(k);read(p);
int w=get_w(),ans=0,ni=pow(pow(w,k-1),p-2);
ans=(ans+calc(ni))%p;
for(int i=k-2;i>=0;i--)
ni=ni*w%p,ans=(ans+calc(ni))%p;
printf("%lld\n",ans*pow(k,p-2)%p);
}
return 0;
}