首先求出一个原根g,那么单位根w取
g
p
−
1
k
g^{\frac{p-1}k}
gkp−1
性质是这样的:
w
n
w^n
wn的
0
0
0次到
k
−
1
k-1
k−1次相加取平均数为
1
1
1,当且仅当
k
∣
n
k|n
k∣n。
构造多项式
F
(
x
)
=
(
I
+
x
M
)
n
F(x)=(I+xM)^n
F(x)=(I+xM)n,I是单位矩阵,M是Fib数列的转移矩阵,那么其k次项系数显然就是
(
n
k
)
\binom n k
(kn)。这样做完了。
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<cmath>
#define lint long long
#define debug(x) cerr<<#x<<"="<<x
#define sp <<" "
#define ln <<endl
using namespace std;
int p,pri[100];
inline int fast_pow(int x,int k,int ans=1)
{ for(;k;k>>=1,x=(lint)x*x%p) (k&1)?ans=(lint)ans*x%p:0;return ans; }
inline int get_yg(int p)
{
int x=p-1,s=sqrt(x+0.5),c=0;
for(int i=2;i<=s;i++)
if(x%i==0)
{
pri[++c]=i,x/=i;
while(x%i==0) x/=i;
}
if(x>1) pri[++c]=x;int g=2;
while(g<p-1)
{
int can_be_yg=1;
for(int i=1;i<=c;i++)
if(fast_pow(g,(p-1)/pri[i])==1)
{ can_be_yg=0;break; }
if(can_be_yg) return g;g++;
}
return p-1;
}
inline int tms(int (*a)[3],int (*b)[3],int (*c)[3])
{
static int w[3][3];
for(int i=1;i<=2;i++)
for(int j=1;j<=2;j++) w[i][j]=0;
for(int i=1;i<=2;i++)
for(int k=1;k<=2;k++)
for(int j=1;j<=2;j++)
w[i][j]+=(lint)a[i][k]*b[k][j]%p;
for(int i=1;i<=2;i++)
for(int j=1;j<=2;j++) c[i][j]=w[i][j]%p;
return 0;
}
inline int fast_pow(int (*a)[3],int (*b)[3],lint k)
{
for(int i=1;i<=2;i++) for(int j=1;j<=2;j++) b[i][j]=(i==j);
for(;k;k>>=1ll,tms(a,a,a)) (k&1ll)?tms(a,b,b):0;return b[1][1];
}
inline int calc(int w,lint n)
{
static int a[3][3],b[3][3];
for(int i=1;i<=2;i++)
for(int j=1;j<=2;j++)
a[i][j]=(i==j)+w*(i!=2||j!=2);
return fast_pow(a,b,n),b[1][1];
}
int main()
{
int T;scanf("%d",&T);
while(T--)
{
lint n;int k;scanf("%lld%d%d",&n,&k,&p);
int g=get_yg(p),wn=fast_pow(g,(p-1)/k),ans=0;
for(int i=0,w=1;i<k;i++,w=(lint)w*wn%p) (ans+=calc(w,n))%=p;
printf("%lld\n",(lint)ans*fast_pow(k,p-2)%p);
}
return 0;
}