#线性筛,斐波那契数列,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);
}
posted @ 2020-03-08 13:20  lemondinosaur  阅读(164)  评论(0编辑  收藏  举报