[HDU6755]Fibonacci Sum

题意

定义Fibonacci 数列:

F 0 = 0 , F 1 = 1 F n = F n − 1 + F n − 2   ( n > 1 ) F_0=0,F_1=1\\ F_n=F_{n-1}+F_{n-2}\ (n>1) F0=0,F1=1Fn=Fn1+Fn2 (n>1)

给定整数 N , c , k N,c,k N,c,k,求
∑ n = 0 N F n c k m o d    1 0 9 + 9 \sum_{n=0}^NF_{nc}^k\mod{10^9+9} n=0NFnckmod109+9
N , c ≤ 1 0 18 , k ≤ 1 0 5 N,c\le10^{18},k\le10^5 N,c1018,k105.


题解

根据Fibonacci数列通项公式 F n = 1 5 [ ( 1 + 5 2 ) n − ( 1 − 5 2 ) n ] \displaystyle F_n=\frac{1}{\sqrt5}\Big[(\frac{1+\sqrt5}{2})^n-(\frac{1-\sqrt5}{2})^n\Big] Fn=5 1[(21+5 )n(215 )n],有
∑ n = 0 N F n c k = ∑ n = 0 N ( 1 5 ) k [ ( 1 + 5 2 ) n c − ( 1 − 5 2 ) n c ] k , a c = ( 1 + 5 2 ) c , b c = ( 1 − 5 2 ) c = ( 1 5 ) k ∑ n = 0 N ∑ i = 0 k ( − 1 ) i ( k i ) ( a c k − i b c i ) n , t i = a c k − i b c i = ( 1 5 ) k ∑ i = 0 k ( − 1 ) i ( k i ) ∑ n = 0 N t i n = ( 1 5 ) k ∑ i = 0 k ( − 1 ) i ( k i ) ⋅ { t i N + 1 − 1 t i − 1 , t i ≠ 1 N + 1 , t i = 1 \begin{aligned} \sum_{n=0}^NF_{nc}^k&=\sum_{n=0}^N\Big(\frac{1}{\sqrt5}\Big)^k\Big[(\frac{1+\sqrt5}{2})^{nc}-(\frac{1-\sqrt5}{2})^{nc}\Big]^k,\quad a_c=(\frac{1+\sqrt5}{2})^c,b_c=(\frac{1-\sqrt5}{2})^c\\ &=\Big(\frac{1}{\sqrt5}\Big)^k\sum_{n=0}^N\sum_{i=0}^k(-1)^i{k\choose i}(a_c^{k-i}b_c^i)^n,\quad t_i=a_c^{k-i}b_c^i\\ &=\Big(\frac{1}{\sqrt5}\Big)^k\sum_{i=0}^k(-1)^i{k\choose i}\sum_{n=0}^Nt_i^n\\ &=\Big(\frac{1}{\sqrt5}\Big)^k\sum_{i=0}^k(-1)^i{k\choose i}\cdot\left\{\begin{aligned} \frac{t_i^{N+1}-1}{t_i-1},&\quad t_i\neq 1\\ N+1,&\quad t_i=1 \end{aligned}\right. \end{aligned} n=0NFnck=n=0N(5 1)k[(21+5 )nc(215 )nc]k,ac=(21+5 )c,bc=(215 )c=(5 1)kn=0Ni=0k(1)i(ik)(ackibci)n,ti=ackibci=(5 1)ki=0k(1)i(ik)n=0Ntin=(5 1)ki=0k(1)i(ik)ti1tiN+11,N+1,ti=1ti=1

暴力预处理出 38300801 6 2 ≡ 61699199 3 2 ≡ 5 ( m o d 1 0 9 + 9 ) 383008016^2\equiv616991993^2\equiv5\pmod{10^9+9} 383008016261699199325(mod109+9) ,任取一个作为 5 \sqrt5 5 模意义下的值即可。
再求出 a ≡ 1 + 5 2 ( m o d 1 0 9 + 9 ) , b ≡ 1 − 5 2 ( m o d 1 0 9 + 9 ) ) \displaystyle a\equiv\frac{1+\sqrt5}{2}\pmod{10^9+9},b\equiv\frac{1-\sqrt5}{2}\pmod{10^9+9)} a21+5 (mod109+9),b215 (mod109+9))
计算快速幂的时候用 a b ≡ a b m o d    P − 1 ( m o d P ) a^b\equiv a^{b\mod{P-1}}\pmod{P} ababmodP1(modP)降幂优化。
t i t_i ti可以通过 t i = t i − 1 ⋅ ( b a ) c \displaystyle t_i=t_{i-1}\cdot(\frac ba)^c ti=ti1(ab)c递推计算。
时间复杂度 O ( ∑ k log ⁡ P ) O(\sum k\log P) O(klogP)

const int P = 1e9 + 9, sqrt5 = 383008016, invsqrt5 = 276601605, A = 691504013,
          B = 308495997;
inline int FastExp(int a, ll b) {
    int x = 1;
    for (b %= P - 1; b; b >>= 1, a = (ll)a * a % P)
        if (b & 1)
            x = (ll)x * a % P;
    return x;
}
inline void Solve() {
    ll Ans = 0;
    int t = FastExp(FastExp(A, k), c),
        q = FastExp((ll)B * FastExp(A, P - 2) % P, c);
    for (int i = 0; i <= k; ++i, t = (ll)t * q % P)
        if (t == 1)
            Ans += ((i & 1) ? -1 : 1) * (ll)C(k, i) * ((n + 1) % P) % P;
        else
            Ans += ((i & 1) ? -1 : 1) * (ll)C(k, i) * (FastExp(t, n + 1) - 1) % P * FastExp(t - 1, P - 2) % P;

    Ans = (Ans % P + P) % P * FastExp(invsqrt5, k) % P;
    printf("%lld\n", Ans);
}

预处理分块幂 a n = a S ⌊ n S ⌋ + ( n m o d    S ) = a S ⌊ n S ⌋ ⋅ a n m o d    S = f a , 1 ( ⌊ n S ⌋ ) ⋅ f a , 2 ( n m o d    S ) \displaystyle a^n=a^{S\lfloor\frac{n}{S}\rfloor+(n\mod{S})}=a^{S\lfloor\frac{n}{S}\rfloor}\cdot a^{n\mod{S}}=f_{a,1}(\lfloor\frac{n}{S}\rfloor)\cdot f_{a,2}(n\mod{S}) an=aSSn+(nmodS)=aSSnanmodS=fa,1(Sn)fa,2(nmodS),取 S = 2 15 , S 2 > 1 0 9 + 9 S=2^{15},S^2>10^9+9 S=215,S2>109+9,将取模和整除转化为位运算。这样快速幂就可以 O ( 1 ) O(1) O(1)求出。
假设 t i ≠ 1 t_i\neq 1 ti=1,则有
∑ n = 0 N F n c k = ( 1 5 ) k 1 ∏ i = 0 k ( t i − 1 ) ∑ i = 0 k ( − 1 ) i ( k i ) ( t i N + 1 − 1 ) ∏ j ≠ i ( t i − 1 ) \sum_{n=0}^NF_{nc}^k=\Big(\frac{1}{\sqrt5}\Big)^k\frac{1}{\prod\limits_{i=0}^k(t_i-1)}\sum_{i=0}^k(-1)^i{k\choose i}(t_i^{N+1}-1)\prod_{j\neq i}(t_i-1) n=0NFnck=(5 1)ki=0k(ti1)1i=0k(1)i(ik)(tiN+11)j=i(ti1)

预处理出 t i − 1 t_i-1 ti1的前缀积和后缀积,就可以只需要算一次逆元,再特判一下存在 t i = 1 t_i=1 ti=1的情况即可。
注意到 a b = − 1 ab=-1 ab=1,于是有
a k − i b i = { ( − 1 ) i a k − 2 i , i ≤ k 2 ( − 1 ) k − i b 2 i − k , i > k 2 a^{k-i}b^i= \left\{\begin{aligned} (-1)^ia^{k-2i},&\quad i\le\frac{k}{2}\\ (-1)^{k-i}b^{2i-k},&\quad i>\frac{k}{2} \end{aligned}\right. akibi=(1)iak2i,(1)kib2ik,i2ki>2k

这样替换就可以在求 t i t_i ti t i N + 1 t_i^{N+1} tiN+1时少做几次乘法和取模运算。
时间复杂度 O ( P + ∑ k ) O(\sqrt P+\sum k) O(P +k)

#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 5, S = (1 << 15) - 1, P = 1e9 + 9, sqrt5 = 383008016,
          invsqrt5 = 276601605, A = 691504013, B = 308495997;
typedef long long ll;
typedef int arr[N];
/*-----------------------------------------------------------------*/
int k;
arr g, pre, suf, fac = {1}, ifac, f_1[2] = {{1}, {1}}, f_2[2] = {{1}, {1}};
ll n, c;
inline int C(int n, int m) {
    return n >= m ? (ll)fac[n] * ifac[n - m] % P * ifac[m] % P : 0;
}
inline int FastExp(int a, int b) {
    int x = 1;
    for (; b; b >>= 1, a = (ll)a * a % P)
        if (b & 1)
            x = (ll)x * a % P;
    return x;
}
inline int BlockExp(int t, int b) {//t=0表示底数为A;t=1表示底数为B
    return (ll)f_1[t][b >> 15] * f_2[t][b & S] % P;
}
inline ll Sign(ll x) { return x & 1 ? -1 : 1; }
inline void Solve() {
    //prepare
    int Sign1 = c & 1, Sign2 = (c & 1) * ((n + 1) & 1);//记录几个特殊指数的奇偶性
    c %= P - 1;
    ll Ans = 0, n1c = (n + 1) % (P - 1) * c % (P - 1);
    for (int i = 0; i <= (k - 1) / 2; ++i)
        g[i] = Sign(Sign1 * i & 1) * BlockExp(0, c * (k - 2 * i) % (P - 1)) - 1;
    if (!(k & 1))
        g[k / 2] = Sign((Sign1 * k / 2) & 1) == 1 ? 1 : -2;
    for (int i = k / 2 + 1; i <= k; ++i)
        g[i] = Sign(Sign1 * (k - i) & 1) * BlockExp(1, c * (2 * i - k) % (P - 1)) - 1;
    pre[0] = 1, suf[k] = 1;
    for (int i = 1; i <= k; ++i)
        pre[i] = (ll)pre[i - 1] * g[i - 1] % P;
    for (int i = k - 1; i >= 0; --i)
        suf[i] = (ll)suf[i + 1] * g[i + 1] % P;
    //calculate answer
    for (int i = 0; i <= (k - 1) / 2; ++i)
        Ans += Sign(i) * C(k, i) * (Sign(Sign2 * i) * BlockExp(0, n1c * (k - 2 * i) % (P - 1)) - 1) %  P * pre[i] % P * suf[i] % P;
    if (!(k & 1)) {
        int t = Sign(Sign1 * k / 2);
        Ans += Sign(k / 2) * C(k, k / 2) * (t == 1 ? (n + 1) % P : (n + 1) & 1) % P * pre[k] % P * g[k] % P;
    }
    for (int i = k / 2 + 1; i <= k; ++i)
        Ans += Sign(i) * C(k, i) * (Sign(Sign2 * (k - i)) * BlockExp(1, n1c * (2 * i - k) % (P - 1)) - 1) % P * pre[i] % P * suf[i] % P;
    Ans = (Ans % P + P) % P * FastExp(invsqrt5, k) % P * FastExp((ll)pre[k] * g[k] % P, P - 2) % P;
    printf("%lld\n", (Ans % P + P) % P);
}
int main() {
    for (int i = 1; i <= 1e5; ++i)
        fac[i] = (ll)fac[i - 1] * i % P;
    ifac[100000] = FastExp(fac[100000], P - 2);
    for (int i = 1e5; i >= 1; --i)
        ifac[i - 1] = (ll)ifac[i] * i % P;
    for (int i = 1; i <= S; ++i)
        f_2[0][i] = (ll)f_2[0][i - 1] * A % P,
        f_2[1][i] = (ll)f_2[1][i - 1] * B % P;
    f_1[0][1] = (ll)f_2[0][S] * A % P;
    f_1[1][1] = (ll)f_2[1][S] * B % P;
    for (int t = 0; t <= 1; ++t)
        for (int i = 2; i <= S; ++i)
            f_1[t][i] = (ll)f_1[t][i - 1] * f_1[t][1] % P;
    scanf("%*d");
    while (~scanf("%lld%lld%d", &n, &c, &k))
        Solve();
    return 0;
}

卡常害人

  • 8
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值