ZOJ3774_Power of Fibonacci

求fibonacci数列前N个数的K次方和。

通项公式:F[n]=((1+sqrt(5))/sqrt(5)-(1-sqrt(5))/sqrt(5))/sqrt(5)。

有点乱,不过由于可以保证最后的结果是一个整数,所有所有的根号都可以化为整数进行取模和逆元运算。

首先解二次同余方程,X^2=n (mod M),显然,当n=5的时候,X就可以相当于5了。

后面的都可以替换掉。

然后就变成了 F[n]=(A^n+B^n)*C。

这里通过二项式展开,分别对每一项进行计算,同时又可以发现,每一项求和其实是一个等比数列,于是,就可以直接搞了。

召唤代码君:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#define M 1000000009
#define maxn 100100
typedef long long ll;
using namespace std;

ll w,a,m,root,inv;
ll A[maxn],B[maxn];
ll n,k,ans,cur,now;
ll AAA,BBB;
int T;

struct twice{
    ll A,B;
    twice() {}
    twice(ll AA,ll BB) { A=AA,B=BB; }
    void mul(twice T){
        ll aa=A*T.A+(B*T.B)%M*w,bb=A*T.B+B*T.A;
        A=aa%M,B=bb%M;
    }
};

ll power(ll A,ll B,ll C)
{
    ll tot=1;
    while (B){
        if (B&1) tot=tot*A%C;
        A=A*A%C,B>>=1;
    }
    return tot;
}

twice power(twice T,ll y)
{
    twice C(1,0);
    while (y){
        if (y&1) C.mul(T);
        T.mul(T),y>>=1;
    }
    return C;
}

ll getroot()
{
    for (;;){
        a=rand()%M;
        w=(a*a-5+M)%M;
        if (power(w,M/2,M)!=1) break;
    }
    return power(twice(a,1),(M+1)/2).A;
}

void _init()
{
    root=getroot();
    A[0]=B[0]=1;
    for (int i=1; i<maxn; i++){
        A[i]=(A[i-1]*i)%M;
        B[i]=power(A[i],M-2,M);
    }
    inv=B[2];
    AAA=(1+root)*inv%M;
    BBB=(M+1-root)*inv%M;
}

int main()
{
    _init();
    scanf("%d",&T);
    while (T--){
        scanf("%lld%lld",&n,&k);
        ans=0;
        for (int i=0; i<=k; i++){
            cur=A[k]*(B[i]*B[k-i]%M)%M;
            if (i&1) cur=M-cur;
            now=power(AAA,k-i,M)*power(BBB,i,M)%M;
            if (now>1) now=((power(now,n+1,M)-now)*power(now-1,M-2,M)%M+M)%M;
                else now=now*n%M;
            (ans+=cur*now)%=M;
        }
        ans=ans*power(root,k*(M-2),M)%M;
        printf("%d
",(int)ans);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/lochan/p/3886884.html