BZOJ2813--奇妙的斐波那契【线性筛】【斐波那契数列】

Description

Fibonacci数列是这样一个数列:
F1 = 1, F2 = 1, F3 = 2 …
Fi = Fi-1 + Fi-2 (当 i >= 3)
pty忽然对这个古老的数列产生了浓厚的兴趣,他想知道:对于某一个Fibonacci数Fi,
有多少个Fj能够整除Fi (i可以等于j),他还想知道所有j的平方之和是多少。

题解

由斐波那契的性质得:
当i,j>2, f[i]|f[j]i|j
所以就把题目转化为:求一个数n的因数个数和所有因数的平方和。
我们想到可以直接枚举每个因数,但是这样做会爆掉,所以要用线性筛。
在筛法时维护以下信息:
g[i]表示i的因数个数
f[i]表示i的所有因数的平方和
k[i]表示i的最小质因数的次数
d[i]表示i除去它的所有最小质因数后剩下的数

分两种情况讨论:
i%p>0,即p是i*p的最小质因数并且第一次出现,
g[ip]=g[i]<<1;f[ip]=f[i]+f[i]p2;k[ip]=1;d[ip]=i;
i%p=0,即p是i*p的最小质因数但不是第一次出现,
k[ip]=k[i]+1;d[ip]=d[i];g[ip]=g[i]/(k[i]+1)(k[d[ip]]+1);f[ip]=f[d[i]]+f[i]p2;
最后,由于f[2]=1,所以f[2]是所有数的因数,但是只有为偶数的下标才是2的倍数,所以n为奇数的情况需要特判。
代码如下:

#include<cstdio>
#include<cstring>
#include<algorithm>
#define LL long long
#define maxn 10000006
#define tt 1000000007
using namespace std;
int n,A,B,C,tet,ans1,ans2,prime[maxn],d[maxn],k[maxn],g[maxn],f[maxn];
bool vis[maxn];
int main(){
    freopen("fibnacci.in","r",stdin);
    freopen("fibnacci.out","w",stdout);
    scanf("%d%d%d%d%d",&tet,&n,&A,&B,&C);
    memset(vis,1,sizeof(vis));
    f[1]=g[1]=1;
    for(int i=2;i<=maxn;i++){
        if(vis[i])prime[++prime[0]]=i,g[i]=2,f[i]=((LL)i*i+1)%tt,k[i]=1,d[i]=1;
        for(int j=1;j<=prime[0]&&i*prime[j]<=maxn;j++){
            vis[i*prime[j]]=0;
            if(!(i%prime[j])){
                k[i*prime[j]]=k[i]+1;d[i*prime[j]]=d[i];
                g[i*prime[j]]=((LL)g[i]/(k[i]+1)*(k[i*prime[j]]+1))%tt;
                f[i*prime[j]]=((LL)f[d[i]]+(LL)f[i]*prime[j]*prime[j])%tt;
                break;
            }
            g[i*prime[j]]=((LL)g[i]<<1)%tt;
            f[i*prime[j]]=((LL)f[i]+(LL)f[i]*prime[j]*prime[j])%tt;
            k[i*prime[j]]=1;d[i*prime[j]]=i;
        }
    }
    while(tet--){
        (ans1+=g[n]+(n&1))%=tt;(ans2+=f[n]+4*(n&1))%=tt;
        n=((LL)n*A+B)%C+1;
    }
    printf("%d\n%d",ans1,ans2);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值