• 2020杭电多校第一场 1005 Fibonacci Sum(二次剩余,Fibonacci通项公式)


    题意

    Fibonacci定义如下:

    输入三个数n,c,k,计算如下表达式的值:

    1

    并将结果对1e9+9取模

    思路:

    Fibonacci的通项公式如下:

    (F_i=frac{1}{sqrt{5}}*[(frac{1+sqrt{5}}{2})^i-(frac{1-sqrt{5}}{2})^i])

    由于5是模1e9+9下的二次剩余,因此可以直接将该公式带入表达式中求解,其中(sqrt5)用5的二次剩余383008016代替。

    令A=(frac{1+sqrt{5}}{2}),B=(frac{1-sqrt{5}}{2}),求得A=691504013,B=308495997

    ((F_{ic})^k=(frac{1}{sqrt{5}})^k*(A^{ic}-B^{ic})^k)

    利用二项式定理展开后,((F_{ic})^k=(frac{1}{sqrt{5}})^k* sum_{j=0}^k[(-1)^{k-j}*C_k^j*A^{icj}*B^{ic(k-j)}])

    发现所有(F_i)中j相同的项可以合并,只看(A imes B)部分,合并之后是一个等比数列,初项和公比均为(A^{cj}*B^{c(k-j)}),有n项,利用等比数列求和公式可以得到其和为(x*frac{x^n-1}{x-1}),其中(x=A^{cj}*B^{c(k-j)})

    就可以得到(ans=(frac{1}{sqrt{5}})^k* sum_{j=0}^k[(-1)^{k-j}*C_k^j*x*frac{x^n-1}{x-1}])

    优化

    直接在循环中用快速幂跑这个代码会T,需要两种优化方法:
    (1)利用欧拉降幂公式

    因为1e9+9是质数,因此gcd(x,p)一定为1,计算中所有需要求幂的都可以把指数对1e9+8取模

    (2)在循环中需要用到x,x不需要每次用快速幂进行求,因为可以发现当前的x和前一项相比,只要乘上(A^c/B^c)就可以了,可以少算一次快速幂。

    (3)取模数一定要加const,加了之后至少快了500ms,我艹

    代码:

    #pragma GCC optimize(2)
    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int maxn=1e5+5;
    const ll sqrt5=383008016;
    const ll A=691504013,B=308495997;
    const ll P=1e9+9;
    ll fac[maxn],finv[maxn];
    ll fp(ll b,ll p){
        ll ans=1;
        while(p){
            if(p&1){
                ans=ans*b%P;
            }
            p>>=1;
            b=b*b%P;
        }
        return ans;
    }
    void init(int n){
        fac[0]=1;
        for(int i=1;i<=n;i++){
            fac[i]=fac[i-1]*i%P;
        }
        finv[n]=fp(fac[n],P-2);
        for(int i=n-1;i>=0;i--){
            finv[i]=finv[i+1]*(i+1)%P;
        }
    }
    ll C(ll n,ll m){
        if(m<0 || m>n) return 0;
        return fac[n]*finv[n-m]%P*finv[m]%P;
    }
    ll solve(ll n,ll c,ll k){
        ll A_C=fp(A,c%(P-1));
        ll B_C=fp(B,c%(P-1));
        ll inv_B_C=fp(B_C,P-2);
        ll base=fp(B_C,k);
        ll multi=A_C*inv_B_C%P;
        ll ans=0;
        for(ll i=0;i<=k;i++){
            ll temp;
            if(base==1){
                temp=n%P;
            }
            else{
                temp=base*(fp(base,n%(P-1))-1+P)%P*fp(base-1,P-2)%P;
            }
            ll temp2=C(k,i)*temp%P;
            if((k-i)&1){
                ans-=temp2;
                ans=(ans+P)%P;
            }
            else{
                ans+=temp2;
                ans=(ans+P)%P;
            }
            base=base*multi%P;
        }
        ll inv_sqrt5=fp(sqrt5,P-2);
        ans=ans*fp(inv_sqrt5,k)%P;
        return ans;
    }
    int main () {
        init(100000);
        int T;
        scanf("%d",&T);
        while(T--){
            ll n,c,k;
            scanf("%lld%lld%lld",&n,&c,&k);
            ll ans=solve(n,c,k);
            printf("%lld
    ",ans);
        }
    }
    
  • 相关阅读:
    postgreSQL入门命令
    JDBC连接数据库
    nano编辑器使用教程
    Linux上vi(vim)编辑器使用教程
    【编程思想】【设计模式】【行为模式Behavioral】状态模式State
    【编程思想】【设计模式】【行为模式Behavioral】Specification
    【编程思想】【设计模式】【行为模式Behavioral】registry
    【编程思想】【设计模式】【行为模式Behavioral】Publish_Subscribe
    【编程思想】【设计模式】【行为模式Behavioral】观察者模式Observer
    【编程思想】【设计模式】【行为模式Behavioral】备忘录模式Memento
  • 原文地址:https://www.cnblogs.com/ucprer/p/13361712.html
Copyright © 2020-2023  润新知