2019牛客暑期多校训练营(第九场)A.The power of Fibonacci(循环节)

题意

{ f 0 = 0 f 1 = 1 f n = f n − 1 + f n − 2 , n ≥ 2 \left\{\begin{matrix} f_0=0\\ f_1=1\\ f_n=f_{n-1}+f_{n-2},n\geq 2 \end{matrix}\right. f0=0f1=1fn=fn1+fn2,n2
给你 n n n m m m
∑ i = 0 n f i m   % 1000000000 \sum_{i=0}^{n}f_{i}^m \ \% 1000000000 i=0nfim %1000000000
1 ≤ n ≤ 1 0 9 , 1 ≤ m ≤ 1000 1\leq n\leq 10^9,1\leq m \leq 1000 1n109,1m1000

思路

Fibonomial coefficients+常系数线性递推
由于在 m o d = 1000000000 mod=1000000000 mod=1000000000 5 5 5的二次剩余不存在,所以不能变为通项的那种方法来做。

那我们可以换一种思路,易知在模意义下斐波那契数列的循环节和次幂的循环节是一样的,原数是循环的那这个数的次幂也是循环的。但是 m o d mod mod太大了,也可以直接去找循环节,直接去找的循环节为1500000000,对于计算答案来说没有什么贡献。但有

m o d = 1000000000 = 2 9 ∗ 5 9 = 512 ∗ 1953125 mod=1000000000=2^9*5^9=512*1953125 mod=1000000000=2959=5121953125

我们可以求出在模 512 512 512下的 a 1 = ∑ i = 0 n f i m   %   512 a_1=\sum_{i=0}^{n}f_{i}^m\ \% \ 512 a1=i=0nfim % 512和在模 1953125 1953125 1953125 a 2 = ∑ i = 0 n f i m   %   1953125 a_2=\sum_{i=0}^{n}f_{i}^m\ \% \ 1953125 a2=i=0nfim % 1953125,那么我们就可以得到同余方程组
{ x ≡ a 1 m o d    512 x ≡ a 2 m o d    1953125 \left\{\begin{matrix} x\equiv a_1 \mod 512\\ x\equiv a_2 \mod 1953125 \end{matrix}\right. {xa1mod512xa2mod1953125
对于这个同余方程组我们套一个中国剩余定理 ( C R T ) (CRT) (CRT)就可以得到最终 m o d    1000000000 \mod 1000000000 mod1000000000的答案了
下面我再说一下怎么求解 a 1 a_1 a1 a 2 a_2 a2

我们先找一下斐波那契数列对于 512 512 512 1953125 1953125 1953125的循环节,由于这两个数都不大,直接用for循环就可以找到,我们得到的循环节分别是 l o o p 1 = 768 loop_1=768 loop1=768, l o o p 2 = 7812500 loop_2=7812500 loop2=7812500
我们存下在模 512 512 512 1953125 1953125 1953125下的斐波那契数列的 m m m次幂的和,由于存在循环节所以,斐波那契数列的 m m m次幂的和也是同样在 768 768 768, 7812500 7812500 7812500循环的,所以我们前缀和只用存到 768 768 768, 7812500 7812500 7812500就够了记为 s u m 1 [ 768 ] , s u m 2 [ 7812500 ] sum1[768],sum2[7812500] sum1[768],sum2[7812500]

对于给你的 n n n,由于前缀和在 768 768 768, 7812500 7812500 7812500是重复的,那么答案由两部分构成一部分是重复完整的循环,另一部分就是最后一段多出来的部分,即
a 1 = ( n 768 ∗ s u m 1 [ 768 ] + s u m 1 [ n % 768 ] ) % m o d a_1=(\frac{n}{768}*sum1[768]+sum1[n\%768])\% mod a1=(768nsum1[768]+sum1[n%768])%mod
a 2 = ( n 7812500 ∗ s u m 1 [ 7812500 ] + s u m 1 [ n % 7812500 ] ) % m o d a_2=(\frac{n}{7812500}*sum1[7812500]+sum1[n\%7812500])\% mod a2=(7812500nsum1[7812500]+sum1[n%7812500])%mod
然后套用中国剩余定理就可以了
p s : ps: ps:由于同余式有 a ≡ b m o d    p → a ≡ b m o d    d a\equiv b \mod p\rightarrow a\equiv b \mod d abmodpabmodd其中 d ∣ p d|p dp,所以我们在做快速幂和求幂次前缀和还有斐波那契数列的时候都可以模上 m o d = 1000000000 mod=1000000000 mod=1000000000,又有模数都一样了之后前缀和与斐波那契数列只用开一个数组就可以得到答案了

#include<bits/stdc++.h>
using namespace std;
const int l1=768;
const int l2=7812500;
const int MOD=1e9;
long long m[]= {512,1953125};
long long f[l2+5];
long long sum[l2+5];
long long quickmod(long long a,long long b)
{
    long long ans=1;
    while(b)
    {
        if(b&1)
            ans=ans*a%MOD;
        b>>=1;
        a=a*a%MOD;
    }
    return ans;
}
void exgcd(long long  a1,long long b,long long &x,long long &y)
{
    if(b==0)
    {
        x=1;
        y=0;
        return ;
    }
    exgcd(b,a1%b,x,y);
    long long t=x;
    x=y;
    y=t-(a1/b)*y;
}
long long CRT(long long a[],long long m[],int n)
{
    long long M=1,ans=0,t,x,y;
    for(int i=0; i<n; i++)
    {
        M*=m[i];
    }
    for(int i=0; i<n; i++)
    {
        t=M/m[i];
        exgcd(t,m[i],x,y);
        ans=(ans+a[i]*x*t)%M;
    }
    return (ans+M)%M;
}
int main()
{
    int n,_m;
    scanf("%d%d",&n,&_m);
    f[0]=0;
    f[1]=sum[1]=1;
    for(int i=2; i<l2+5; i++)
    {
        f[i]=(f[i-1]+f[i-2])%MOD;
        sum[i]=(sum[i-1]+quickmod(f[i],_m))%MOD;
    }
    long long a[2];
    a[0]=((n/l1)*sum[l1]+sum[n%l1])%MOD;
    a[1]=((n/l2)*sum[l2]+sum[n%l2])%MOD;
    long long ans=CRT(a,m,2);
    printf("%lld\n",ans);
    return 0;
}
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值