[BZOJ2813]奇妙的Fibonacci(线性筛)

题目: 我是超链接
题解: 通过打表找到的规律我们发现 Fj|Fi等价于j|iF j | F i 等 价 于 j | i (除了f[2]=1的2之外,这个最后特判就可以)
这个题目就相当于问约数个数和和约数平方和,这两个函数都是可以线筛出来的
首先是约数个数和,如果一个数 a=pk11pk22pk33....a = p 1 k 1 p 2 k 2 p 3 k 3 . . . . 那么他的约数个数是 (k1+1)?(k2+1)?...( k 1 + 1 ) ? ( k 2 + 1 ) ? . . . ,这个不难考虑
d(i)表示i的约数个数,e(i)表示最小质因数的指数,那么线筛三步走
当i是个质数时,d(i)=2,e(i)=1
当i不是个质数,枚举质数p,由i转移过去,再分类
p/|ip ? | i ,这个质数第一次出现,那么 e(ip)=1,d(ip)=d(i)?2=d(i)?d(pri(j))e ( i p ) = 1 , d ( i p ) = d ( i ) ? 2 = d ( i ) ? d ( p r i ( j ) )
p|ip | i ,即以前出现过这个质数, e(ip)=e(i)+1,d(ip)=d(i)/(e(i)+1)?(e(i)+2)e ( i p ) = e ( i ) + 1 , d ( i p ) = d ( i ) / ( e ( i ) + 1 ) ? ( e ( i ) + 2 ) ,就是除以这个质数出现的次数+1然后更改为新的次数


然后是第二问约数平方和
g(i)表示约数平方和,h(i)表示排除最小质因数部分的约数平方和,依然线筛三步走
当i是个质数时, g(i)=i2+1,h(i)=1g ( i ) = i 2 + 1 , h ( i ) = 1
当i不是个质数,枚举质数p,由i转移过去,再分类
p/|ip ? | i ,这个质数第一次出现,那么他本来就不含这个质数,可以给h(ip)赋为i,加上这一个质数之后,整个约数的平方和会增加上这个pri,那么g(ip)就是g(i)+pri*pri*g(i)
【[BZOJ2813]奇妙的Fibonacci(线性筛)】 p|ip | i ,即以前出现过这个质数,那么我把以前不含这个质数的平方和再加上有了这一群一样的质数之后的平方和,显然h(i)中一定不含有带pri的约数,所以可以先用i中所有约数乘上pri构造出含有pri的约数,再接收g(h(i))来累加所有不含pri的约数
代码:

#include #define LL long long using namespace std; const int mod=1e9+7; const int maxn=10000000; const int N=10000005; int tot,e[N],h[N]; bool ss[N]; LL pri[N],d[N],g[N]; void init(int n) { d[1]=g[1]=1; for (int i=2; i<=n; i++) { if (!ss[i]) { pri[++tot]=i; d[i]=2; e[i]=1; g[i]=((LL)i*i)%mod+1; h[i]=1; } for (int j=1; j<=tot&&pri[j]*i<=n; j++) { ss[pri[j]*i]=1; if (i%pri[j]==0) { d[i*pri[j]]=d[i]/(e[i]+1)*(LL)(e[i]+2)%mod; e[i*pri[j]]=e[i]+1; g[i*pri[j]]=(g[h[i]]+(LL)g[i]*pri[j]%mod*pri[j]%mod)%mod; h[i*pri[j]]=h[i]%mod; break; } d[i*pri[j]]=d[i]*(LL)2%mod; e[i*pri[j]]=1; g[i*pri[j]]=(g[i]+(LL)pri[j]*(LL)pri[j]%mod*g[i]%mod)%mod; h[i*pri[j]]=i; } } } int main() { int Q,q,a,b,c; scanf("%d%d%d%d%d",&Q,&q,&a,&b,&c); init(c); LL A=0,B=0; for (int t=1; t<=Q; t++) { A=(A+d[q])%mod; if (q&1) A=(A+1)%mod; B=(B+g[q])%mod; if (q&1) B=(B+4)%mod; q=((LL)q*(LL)a%c+b)%c+1; } printf("%lld\n%lld",A,B); }

    推荐阅读