给定$n,k,p$,求
$$\sum_{i=0}^{\lfloor \frac{n}{k} \rfloor} {n \choose ik}F_{ik}$$
其中$F_0=F_1=1$,且$\forall n \ge 2,F_i=F_{i-1}+F_{i-2}$
答案对$p$取模
$1 \le n \le 10^{18}$
$1 \le k \le 20000$
$1 \le p \le 10^9$
$p$是素数
$p \bmod k = 1$
也就是说求
$$\sum_{i=0}^{n} {n \choose i} F_i [k \mid i]$$
通过套用二项式定理,有
$$f(x)=(Ax+I)^n=\sum_{i=0}^{n} {n \choose i}A^ix^iI^{n-i}$$
再套用单位根反演,有
$$T=\frac{\sum_{i=0}^{k-1}f(\omega_k^i)}{k}$$
然后就做完了,答案就是矩阵$T$的左上角
那么给定素数$p$如何求原根呢……
先把$p-1$的所有非$1$和非$p-1$的约数求出来,然后从$2$开始枚举原根$g$
如果对于所有的约数$s_i$,都有$g^{s_i} \ne 1$成立,那么$g$就是$p$的一个原根了
1 #include <bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 ll n, k, p; 5 struct Mat { 6 ll a[2][2]; 7 ll *operator [] (int x) { return a[x]; } 8 Mat() { memset(a, 0, sizeof a); } 9 Mat operator * (Mat b) { 10 Mat c; 11 for(int i = 0 ; i < 2 ; ++ i) 12 for(int j = 0 ; j < 2 ; ++ j) 13 for(int k = 0 ; k < 2 ; ++ k) 14 c[i][j] = (c[i][j] + a[i][k] * b[k][j] % p) % p; 15 return c; 16 } 17 }; 18 19 Mat pw(Mat a, ll n) { 20 Mat c; c[0][0] = c[1][1] = 1; 21 for( ; n ; n >>= 1, a = a * a) if(n & 1) c = c * a; 22 return c; 23 } 24 25 ll pw(ll a, ll b) { 26 ll r = 1; 27 for( ; b ; b >>= 1, a = a * a % p) if(b & 1) r = r * a % p; 28 return r; 29 } 30 ll calc(ll x) { 31 Mat m; 32 m[0][0] = x + 1, m[0][1] = x; 33 m[1][0] = x, m[1][1] = 1; 34 m = pw(m, n); 35 return m[0][0]; 36 } 37 namespace getg { 38 int sig[int(1e7)]; 39 int get(int p) { 40 int x = p - 1, tot = 0; 41 for(int i = 2 ; 1ll * i * i <= x ; ++ i) { 42 if(x % i) continue; 43 sig[++ tot] = i; 44 if(x / i > i) sig[++ tot] = x / i; 45 } 46 for(int g = 2 ; ; ++ g) { 47 bool flag = 1; 48 for(int i = 1 ; i <= tot ; ++ i) { 49 if(pw(g, sig[i]) == 1) { 50 flag = 0; 51 break; 52 } 53 } 54 if(flag) return g; 55 } 56 assert(0); 57 return -1; 58 } 59 } 60 61 void sol() { 62 scanf("%lld%lld%lld", &n, &k, &p); 63 ll g = getg :: get(p); 64 ll wn = pw(g, (p - 1) / k); 65 ll w = 1, ans = calc(w); 66 for(int i = 1 ; i < k ; ++ i) { 67 w = w * wn % p; 68 ans = (ans + calc(w)) % p; 69 } 70 ans = (ans % p + p) % p; 71 printf("%lld\n", ans * pw(k, p - 2) % p); 72 } 73 int main() { 74 int T; scanf("%d", &T); 75 while(T --) sol(); 76 }