#线性筛,斐波那契数列,GCD#BZOJ 2813 奇妙的Fibonacci
题目
有一个斐波那契数列,满足
\[F_n=\begin{cases}1\qquad (n==1)\\1\qquad (n==2)\\F_{n-1}+F_{n-2}\qquad (n>2)\end{cases}
\]
多次询问给出一个\(n\)(\(n=(n'*A+B)\bmod C+1\)),问
\[\sum_{i=1}^n[F_i|F_n]以及\sum_{i=1}^n[F_i|F_n]i^2
\]
\(C\leq 10^7\)
分析
考虑\(F_i|F_n\)也就是\(gcd(F_i,F_n)=F_i(i\leq n)\)
根据\(gcd(F_i,F_n)=F_{gcd(i,n)}\)可以知道相当于询问\(i|n\)
当然我还是证明一下吧
首先引理
\[F_{n+m}=F_{n-1}*F_m+F_n*F_{m+1}
\]
证明:
\[F_{n+1}=F_n+F_{n-1}
\]
\[F_{n+2}=F_n+F_{n+1}=2*F_n+F_{n-1}
\]
\[F_{n+3}=F_{n+2}+F_{n+1}=3*F_n+2*F_{n-1}
\]
以此类推,可以得证
有了这条,还有一个显然的引理就是\(\forall i\in N*,gcd(f_i,f_{i+1})=1\)
想要证明\(GCD\)不容易,一般都是通过更相减损法证明
\[gcd(F_{n+m},F_m)=gcd(F_n,F_m)
\]
那么
\[gcd(F_{n+m},F_m)=gcd(F_{n-1}*F_m+F_n*F_{m+1},F_m)=gcd(F_n*F_{m+1},F_m)=gcd(F_n,F_m)
\]
根据更相减损法和引理推出
那么显然可以通过这样的方法推出\(gcd(F_n,F_m)=F_{gcd(n,m)}\)
注意\(F_0=0\),不然就推不出来
证明写了这么长,那么可以得到答案其实就是
\[\sum_{i=1}^n[gcd(i,n)==i]以及\sum_{i=1}^n[gcd(i,n)==i]i^2
\]
一个是约数个数和,另一个是约数平方的和,分别维护。
先进行质因数分解得出\(n=\prod_{i=1}^k{p_i}^{c_i}\)
那么约数个数和就是\(\prod_{i=1}^k(c_i+1)\)
需要用一个辅助数组表示最小质因数的指数;
约数平方和就是\(\prod_{i=1}^k\frac{{p_i}^{c_i+1}-1}{p_i-1}\)
不需要快速幂,维护最小质因数的答案,用秦九韶算法层层推上去就可以了
可是你的约数平方和会不会爆\(\text{long long}\)??
估摸一下,我觉得不会,大概在\(10^{15}\sim 10^{17}\)这一段吧,
反正构造数据也不会特意卡的是吧
当你兴高采烈的时候会发现有锅,
\(F_2=1\),所以对于奇数要特判
代码
#include <cstdio>
#define rr register
using namespace std;
typedef long long lll;
const int N=10000011,mod=1000000007,M=6700011;
int Cnt,D[N],Mc[N],prime[M]; lll v[N],Si[N],Pp[M];
inline signed mo(int x,int y){return x+y>=mod?x+y-mod:x+y;}
inline void Pro(int n){
v[1]=Si[1]=D[1]=1;
for (rr int i=2;i<=n;++i){
if (!v[i]) v[i]=Si[i]=1ll*i*i+1,D[i]=Mc[i]=2,
prime[++Cnt]=i,Pp[Cnt]=v[i]-1;
for (rr int j=1,t=n/i;j<=Cnt&&prime[j]<=t;++j){
if (i%prime[j]==0){
Mc[i*prime[j]]=Mc[i]+1,
D[i*prime[j]]=D[i]/Mc[i]*Mc[i*prime[j]],
v[i*prime[j]]=v[i]*Pp[j]+1,
Si[i*prime[j]]=Si[i]/v[i]*v[i*prime[j]];
break;
}
Mc[i*prime[j]]=2,v[i*prime[j]]=Pp[j]+1,
D[i*prime[j]]=D[i]*D[prime[j]],
Si[i*prime[j]]=Si[i]*v[i*prime[j]];
}
}
}
signed main(){
rr int ans1=0,ans2=0,Test,Q,A,B,C;
scanf("%d%d%d%d%d",&Test,&Q,&A,&B,&C),Pro(C);
for (;Test;--Test,Q=(1ll*A*Q+B)%C+1)
ans1=mo(ans1,D[Q]+(Q&1)),
ans2=mo(ans2,(Si[Q]+4*(Q&1))%mod);
return !printf("%d\n%d",ans1,ans2);
}