【校内互测】[T1]数学作业(线性筛约数个数)
数学作业
题目描述Description
又是一节晚自习,jn 像往常一样流连于梦乡,但突然被同桌的你戳醒时,却发现数学老师正笑呵呵的站在他面前,“拿出你的数学作业,我要检查”,jn 自然不可能在梦中写作业了,然后喜(sang)闻(xin)乐(bing)见(kuang)的事情发生了,数学老师呵呵一笑,“你不用做今晚数学作业了,不是搞 oi 么,给我算这个吧:Fibonacci 数列是这样一个数列:F1 = 1, F2 = 1, F3 = 2 …Fi = Fi-1 + Fi-2 (当 i >= 3)
对于某一个 Fibonacci 数 Fi,有多少个 Fj 能够整除 Fi (j 可以大于等于 i)共有 m 组询问,输出每个问题答案的和 ans,为了方便输入,ni=(ni−1∗a+b)modc+1
jn 自然不会做了,所以找到你来帮助他
输入Input
从 math.in 输入第一行有五个正整数 m,n1,a,b,c
输出Output
输出到 math.out
样例输入SampleInput
2 2 2 1 8
样例输出SampleOutput
6
数据范围Hint
对于 30%的数据,t≤10,n,a,b,c≤1000
对于 100%的数据,t≤3000000 n,a,b,c≤1000000
通过打表,发现f[j]f[i]的个数与j|i的个数是相同的,所以只要用线性筛筛出每个数的约数个数就可以了
斐波纳契数列的几条性质:
1.f(0)+f(1)+f(2)+„+f(n)=f(n+2)−1
2.f(1)+f(3)+f(5)+„+f(2n−1)=f(2n)
3.f(2)+f(4)+f(6)+„+f(2n)=f(2n+1)−1
4.[f(0)]2+[f(1)]2+……+[f(n)]2=f(n)⋅f(n+1)
5.f(0)−f(1)+f(2)−……+(−1)n⋅f(n)=(−1)n⋅[f(n+1)−f(n)]+1
6.f(m+n)=f(m−1)⋅f(n−1)+f(m)⋅f(n)利用这一点,可以用程序编出时间复杂度仅为O(logn)的程序。
7.[f(n)]2=(−1)(n−1)+f(n−1)⋅f(n+1)
8.f(2n−1)=[f(n)]2−[f(n−2)]2
9.3f(n)=f(n+2)+f(n−2)
10.f(2n−2m−2)[f(2n)+f(2n+2)]=f(2m+2)+f(4n−2m)[n⟩m≥−1,且n≥1]
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int d[1000010],t[1000010],prime[1000010];
long long m,n,a,b,c,maxn,ans,ask[3000010];
bool p[1000010];
inline void shai()
{
int i,j,k=0;
d[1]=1; t[1]=0;
for(i=2;i<=maxn;++i)
{
if(!p[i]) { prime[++k]=i; t[i]=1; d[i]=2; }
for(j=1;j<=k;++j)
{
if(i*prime[j]>maxn) break;
p[i*prime[j]]=true;
if(i%prime[j]==0)
{
d[i*prime[j]]=d[i]/(t[i]+1)*(t[i]+2);
t[i*prime[j]]=t[i]+1;
break;
}
else d[i*prime[j]]=d[i]*2,t[i*prime[j]]=1;
}
}
return;
}//线性筛约数个数
int main()
{
freopen("math.in","r",stdin);
freopen("math.out","w",stdout);
int i,j;
scanf("%I64d%I64d%I64d%I64d%I64d",&m,&n,&a,&b,&c);
maxn=ask[1]=n;
for(i=2;i<=m;++i) ask[i]=(ask[i-1]*a+b)%c+1,maxn=max(maxn,ask[i]);
shai();
for(i=1;i<=m;++i)
{
if(ask[i]%2==1) ans++;
ans+=d[ask[i]];
}
printf("%I64d\n",ans);
fclose(stdin); fclose(stdout);
return 0;
}