我们要求这个东西
∑ni=0CinFi[i mod k=0]
∑
i
=
0
n
C
n
i
F
i
[
i
m
o
d
k
=
0
]
先不考虑
k|i
k
|
i
这个条件,即只计算
∑ni=0CinFi
∑
i
=
0
n
C
n
i
F
i
设出Fib数列的转移矩阵
A
A
,那么就是
Ai
A
i
的左上角
再考虑二项式定理
(a+b)n=∑ni=0aibn−i
(
a
+
b
)
n
=
∑
i
=
0
n
a
i
b
n
−
i
,在矩阵运算中同样适用(满足分配律,结合律)
那么我们可以得到
接下来考虑构造一个的函数
注意到
k≡1 Mod p
k
≡
1
M
o
d
p
,即
k|p−1,phi(p)=p−1
k
|
p
−
1
,
p
h
i
(
p
)
=
p
−
1
因此我们求出
p
p
的原根,令
w=gp−1k
w
=
g
p
−
1
k
,那么
wi≡1modp
w
i
≡
1
mod
p
当且仅当
k|i
k
|
i
并且有这么个柿子
∑k−1j=0wij=k[i mod k=0]
∑
j
=
0
k
−
1
w
i
j
=
k
[
i
m
o
d
k
=
0
]
证明:当
k|i
k
|
i
时,
wi=1
w
i
=
1
,显然和为
k
k
,否则是个以1为首项,为公比的等比数列,
1−wik1−wi
1
−
w
i
k
1
−
w
i
,分子为0,和为0
那么我们就构造出了我们想要的函数:
1k∑k−1j=0wij=[i mod k=0]
1
k
∑
j
=
0
k
−
1
w
i
j
=
[
i
m
o
d
k
=
0
]
那么最后的答案就是
∑ni=0(ni)Fi[i mod k=0]
∑
i
=
0
n
(
i
n
)
F
i
[
i
m
o
d
k
=
0
]
=
∑ni=0(ni)Ai1k∑k−1j=0wij
∑
i
=
0
n
(
i
n
)
A
i
1
k
∑
j
=
0
k
−
1
w
i
j
=
1k∑k−1j=0∑ni=0(ni)AiIn−iwji
1
k
∑
j
=
0
k
−
1
∑
i
=
0
n
(
i
n
)
A
i
I
n
−
i
w
j
i
=
1k∑k−1j=0wnj∑ni=0(ni)Ai(Iw−j)n−i
1
k
∑
j
=
0
k
−
1
w
n
j
∑
i
=
0
n
(
i
n
)
A
i
(
I
w
−
j
)
n
−
i
=
1k∑k−1j=0wnj(A+Iw−j)n
1
k
∑
j
=
0
k
−
1
w
n
j
(
A
+
I
w
−
j
)
n
注意这里
wij
w
i
j
只能和
I
I
结合到一起不能这样子,因为一般矩阵
A
A
是不满足交换律的,但是单位矩阵特殊,他满足交换律,所以可以弄成
Iw−j
I
w
−
j
这样子
code:
#include<set>
#include<map>
#include<deque>
#include<queue>
#include<stack>
#include<cmath>
#include<ctime>
#include<bitset>
#include<string>
#include<vector>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<climits>
#include<complex>
#include<iostream>
#include<algorithm>
#define ll long long
using namespace std;
const int maxn = 110;
int pwmod(int x,ll k,int mod)
{
int re=1;
for(;k;k>>=1,x=(ll)x*x%mod) if(k&1ll)
re=(ll)re*x%mod;
return re;
}
int Inv(int x,int mod){return pwmod(x,mod-2,mod);}
int t[maxn],tp;
int get_g(int P)
{
int p=P-1;
tp=0;
for(int i=2;i*i<=p;i++) if(p%i==0)
{
t[++tp]=i; while(p%i==0) p/=i;
}
if(p>1) t[++tp]=p;
p=P-1;
for(int i=2;;i++)
{
int ok=1;
for(int j=1;j<=tp;j++)
if(pwmod(i,p/t[j],P)==1) { ok=0;break; }
if(ok) return i;
}
}
ll n;
int K,mod,ans;
inline void add(int &a,const int &b){a+=b;if(a>=mod)a-=mod;}
struct mat
{
int a[2][2];
mat(){memset(a,0,sizeof a);}
friend inline mat operator *(const mat &x,const mat &y)
{
mat re;
for(int i=0;i<2;i++) for(int k=0;k<2;k++)
for(int j=0;j<2;j++) add(re.a[i][j],(ll)x.a[i][k]*y.a[k][j]%mod);
return re;
}
friend inline mat operator ^(const mat &x,const int &y)
{
mat re;
for(int i=0;i<2;i++) for(int j=0;j<2;j++) re.a[i][j]=(ll)x.a[i][j]*y%mod;
return re;
}
friend inline mat operator +(const mat &x,const mat &y)
{
mat re;
for(int i=0;i<2;i++) for(int j=0;j<2;j++) re.a[i][j]=(x.a[i][j]+y.a[i][j])%mod;
return re;
}
}A,one,W;
mat pw(mat x,ll k)
{
mat re=one;
for(;k;k>>=1,x=x*x) if(k&1ll)
re=re*x;
return re;
}
int main()
{
//freopen("tmp.in","r",stdin);
//freopen("tmp.out","w",stdout);
A.a[0][0]=A.a[0][1]=A.a[1][0]=1;
one.a[0][0]=one.a[1][1]=1;
int T;scanf("%d",&T);
while(T--)
{
ans=0;
scanf("%lld%d%d",&n,&K,&mod);
int g=get_g(mod);
int w=pwmod(g,(mod-1)/K,mod),inv=Inv(w,mod),wj=1;
W=one;
for(int j=0;j<K;j++)
{
mat temp=A+W,tn=pw(temp,n);
add(ans,(ll)pwmod(wj,n,mod)*tn.a[0][0]%mod);
if(ans<0) ans+=mod;
W=W^inv; wj=(ll)wj*w%mod;
}
printf("%lld\n",(ll)ans*Inv(K,mod)%mod);
}
return 0;
}