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[i∗p]=g[i]<<1;f[i∗p]=f[i]+f[i]∗p2;k[i∗p]=1;d[i∗p]=i;
∙
i%p=0,即p是i*p的最小质因数但不是第一次出现,
k[i∗p]=k[i]+1;d[i∗p]=d[i];g[i∗p]=g[i]/(k[i]+1)∗(k[d[i∗p]]+1);f[i∗p]=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;
}