bzoj 3328 PYXFIB

给定$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 }
bzoj 3328: PYXFIB

转载于:https://www.cnblogs.com/KingSann/articles/9474714.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值