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

来源:互联网 发布:ubuntu镜像文件下载 编辑:程序博客网 时间:2024/05/01 01:36

=== ===

这里放传送门

=== ===

题解

通过打表找规律某种神秘的启示可以发现:Fj|Fij|i
那么问题就变成了求约数个数还有约数平方和的问题
这两个东西都是可以线筛的
约数个数好办,和BZOJ1968的方法是一样的。
对于约数平方和,我们仍然考虑线筛三步走。
当x是质数的时候,它的约数的平方和就是x2+1,因为它只有x和1两个约数。
当已知f(x)的时候,对x加入一个它原来没有的质因子prm。这个时候用所有原来的约数乘上prm就构造出了一批新约数。原来的约数的平方和就是f(x),而新约数的平方和显然就是f(x)prm2。总之,当x中没有prm这个质因子的时候,f(xprm)=f(x)(prm2+1)=f(x)f(prm)
如果x原来就有prm这个质因子,就不能直接把所有x的因子乘上prm来构造新的约数了,因为这样可能会构造出x原来已经有的约数。设x去掉最小质因子的部分是g(x),显然g(x)中一定不含有带prm的约数,所以可以先用x中所有约数乘上prm构造出含有prm的约数,再接收f(g(x))来累加所有不含prm的约数。那么也就是当x%pom=0的时候,f(x)=f(g(x))+f(x)prm2

代码

#include<cstdio>#include<cstring>#include<algorithm>using namespace std;const long long Mod=1000000007;int m,q,a,b,c,prm[10000010],e[10000010],g[10000010];long long f[10000010],d[10000010],A,B;bool ext[10000010];void get_prime(int N){    f[1]=d[1]=1;    for (int i=2;i<=N;i++){        if (ext[i]==false){            prm[++prm[0]]=i;            d[i]=2;e[i]=1;g[i]=1;            f[i]=((long long)i*i+1)%Mod;        }        for (int j=1;j<=prm[0];j++){            if ((long long)i*prm[j]>N) break;            ext[i*prm[j]]=true;            if (i%prm[j]==0){                e[i*prm[j]]=e[i]+1;                d[i*prm[j]]=(long long)d[i]/(e[i]+1)*(e[i]+2);                g[i*prm[j]]=g[i]%Mod;                f[i*prm[j]]=(f[g[i]]+(long long)f[i]*prm[j]%Mod*prm[j]%Mod)%Mod;                break;            }else{                e[i*prm[j]]=1;                d[i*prm[j]]=d[i]*d[prm[j]];                g[i*prm[j]]=i%Mod;                f[i*prm[j]]=(f[i]+(long long)f[i]*prm[j]%Mod*prm[j]%Mod)%Mod;               }        }    }}int main(){    scanf("%d%d%d%d%d",&m,&q,&a,&b,&c);    get_prime(c);    for (int i=1;i<=m;i++){        long long tmp;        tmp=d[q]+((q&1)?1:0);        A=(A+tmp)%Mod;        tmp=f[q]+((q&1)?4:0);        B=(B+tmp)%Mod;        q=((long long)q*a+b)%c+1;    }     printf("%I64d\n%I64d\n",A,B);    return 0;}

偏偏在最后出现的补充说明

找规律大法好

0 0