Wannafly Winter Camp 2019 Day7 C 斐波那契数列 (矩阵快速幂)

https://zhixincode.com/contest/24/problem/C
题意:定义 F i b n Fib_n Fibn为斐波那契数列的第 n n n项,现在给定 R R R,求 ∑ n = 1 R ( F i b n & ( F i b n − 1 ) ) \sum_{n=1}^{R}(Fib_n\&(Fib_{n}-1)) n=1R(Fibn&(Fibn1))

这个题看上去和lowbit有关,因为对于一个数 x x x x & ( x − 1 ) = x − l o w b i t ( x ) x\&(x-1)=x-lowbit(x) x&(x1)=xlowbit(x),所以题目转变为求 F i b n Fib_n Fibn的前 n n n项和 l o w b i t ( F i b n ) lowbit(Fib_n) lowbit(Fibn)的前 n n n项和然后作差。
斐波那契数列的前 n n n项和 a n s 1 ans1 ans1可以通过矩阵快速幂求得,此处不做详细说明。
l o w b i t ( F i b n ) lowbit(Fib_n) lowbit(Fibn)的前 n n n项和 a n s 2 ans2 ans2就没法通过矩阵快速幂求得了,但通过打表找规律其实可以发现规律(下图为前100项 l o w b i t ( F i b n ) lowbit(Fib_{n}) lowbit(Fibn)的值)
前100项
循环周期为 6 6 6,且每个周期前 5 5 5项固定为 1 、 1 、 2 、 1 、 1 1、1、2、1、1 11211
而第 6 6 6项也是有规律的, 8 8 8出现的周期为 2 2 2 16 16 16出现的周期为 4 4 4 32 32 32出现的周期为 8 8 8……
4 ∗ 2 i 4*2^i 42i出现的周期为 2 i 2^i 2i i = 1 , 2 , 3 … … i=1,2,3…… i=1,2,3
这样就可以快速求出 l o w b i t ( F i b n ) lowbit(Fib_n) lowbit(Fibn)的前 n n n项和 a n s 2 ans2 ans2了,最后的答案即 a n s 1 − a n s 2 ans1-ans2 ans1ans2

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
using namespace std;

long long lowbit(long long x){return x&(-x);}
const long long MOD=998244353;
long long n;
long long b[100];
struct node
{
    long long g[5][5];
}f,res;
void init(node &x)//构造单位矩阵
{
    for(int i=1;i<=3;i++)
        for(int j=1;j<=3;j++)
        if(i==j)x.g[i][j]=1;
        else x.g[i][j]=0;
}
void multiple(node &x,node &y,node &z)//矩阵乘法运算
{
    memset(z.g,0,sizeof(z.g));
    for(int i=1;i<=3;i++)
        for(int j=1;j<=3;j++)
        if(x.g[i][j])
    {
        for(int k=1;k<=3;k++)
        {
            z.g[i][k]+=x.g[i][j]*y.g[j][k];
            z.g[i][k]%=MOD;
        }
    }
}
void quickpow(long long k)//快速幂
{
    init(res);
    node temp=f,t;
    while(k)
    {
        if(k&1)
        {
            multiple(res,temp,t);
            res=t;
        }
        multiple(temp,temp,t);
        temp=t;
        k>>=1;
    }
}
long long solve()
{
    if(n<=1)return 1;
    quickpow(n-1);
    long long ret=res.g[1][1]*1+res.g[1][2]*1;
    ret%=MOD;
    ret+=res.g[1][3]*1;
    ret%=MOD;
    return ret;
}
int T;
int main()
{
    scanf("%d",&T);
    while(T--)
    {
        scanf("%lld",&n);
        f.g[1][1]=1;
        f.g[1][2]=1;
        f.g[1][3]=0;
        f.g[2][1]=0;
        f.g[2][2]=1;
        f.g[2][3]=1;
        f.g[3][1]=0;
        f.g[3][2]=1;
        f.g[3][3]=0;
        long long ans1=solve();
        //printf("%lld\n",ans1);
        long long p=n/6;
        long long ans2=p*6%MOD;
        switch(n%6)
        {
        case 1:
            ans2+=1;break;
        case 2:
            ans2+=2;break;
        case 3:
            ans2+=4;break;
        case 4:
            ans2+=5;break;
        case 5:
            ans2+=6;break;
        }
        b[0]=1;
        for(int i=1;i<=62;i++)
            b[i]=b[i-1]*2;
        for(int i=0;i<=62;i++)
        {
            long long q=p-b[i];
            if(q<0) break;
            ans2+=(q/b[i+1]+1)*b[i]*8;
            ans2%=MOD;
        }
        //printf("%lld\n",ans2);
        printf("%lld\n",(ans1-ans2+MOD)%MOD);
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值