zoukankan      html  css  js  c++  java
  • 【bzoj2813】 奇妙的Fibonacci数列 线性筛

    Description

    Fibonacci数列是这样一个数列:

    F1 = 1, F2 = 1, F3 = 2 . . .

    Fi = Fi-1 + Fi-2 (当 i >= 3)

    pty忽然对这个古老的数列产生了浓厚的兴趣,他想知道:对于某一个Fibonacci数Fi,

    有多少个Fj能够整除Fi (i可以等于j),他还想知道所有j的平方之和是多少。

    Input

    第一行一个整数Q,表示Q个询问。

    第二行四个整数:Q1, A, B, C

    第i个询问Qi = (Qi-1 * A + B) mod C + 1(当i >= 2)

    Output

    Ai代表第i个询问有多少个Fj能够整除FQi。

    Bi代表第i个询问所有j的平方之和。

    输出包括两行:

    第一行是所有的Ai之和。

    第二行是所有的Bi之和。

    由于答案过大,只需要输出除以1000000007得到的余数即可。

    Sample Input

    2
    2 2 1 8

    Sample Output

    6
    55

    Hint

    对于100%的数据保证:Q <= 3*10^6,C <= 10^7,A <= 10^7,B <= 10^7,1 <= Q1<= C

    Sol

    首先我们有((F_i,F_j)=F_{(i,j)})我不会证qwq

    我们钦定(F_i)之后,如果((F_i,F_j)=F_j)那么(F_j)就能够整除(F_i)

    等价于((i,j)=j)

    显然(i)的约数全部满足这一性质。

    所以我们实际要求的是每个数字的约数个数和和约数平方和。

    我们设e[i]为i的最小质因数次数,d[i]为i除去最小质因子之后的商,g[i]为i的约数个数,f[i]为i的约数平方和 。

    那么在线性筛时:

    质数:e[i]=1,d[i]=1,g[i]=2,f[i]=i^2+1;

    记k=i*pri[j];

    i%pri[j]==0:e[k]=e[i]+1,d[k]=d[i],g[k]=g[i]/(e[i]+1)*(e[k]+1),f[k]=f[i]*pri[j]^2+f[d[i]];

    i%pri[j]!=0:e[k]=1,d[k]=i,g[k]=g[i]*2,f[k]=f[i]*(pri[j]^2+1);

    e,d,g的表达式很好理解,f的第一个式子含义是把这个质因子次数+1时,除了这个最小质因子以外的因子平方和都不变,新产生的因数的平方和要乘以这个质因子。f的第二个式子含义是新产生的因数的平方和加上原来的平方和。

    要注意f[2]=1,所以如果x是奇数,没有算入贡献,要特判。

    Code

    #include <cstdio>
    int i,T,x,a,b,c,t,d[10000005],e[10000005],f[10000005],g[10000005],p[10000005],v[10000005],sg,sf,P=1000000007;
    int main()
    {
    	for(g[1]=f[1]=1,i=2;i<=10000000;i++)
    	{
    		if(!v[i]){p[++t]=i;e[i]=d[i]=1;g[i]=2;f[i]=(1ll*i*i+1)%P;}
    		for(int j=1,k;j<=t&&(k=i*p[j])<=10000000;j++)
    		{
    			v[k]=1;
    			if(i%p[j]==0)
    			{
    				e[k]=e[i]+1;g[k]=g[i]/(e[i]+1)*(e[k]+1);d[k]=d[i];f[k]=(1ll*f[i]*p[j]%P*p[j]%P+f[d[i]])%P;
    				break;
    			}
    			else e[k]=1,d[k]=i,g[k]=g[i]<<1,f[k]=f[i]*(1ll*p[j]*p[j]%P+1)%P;
    		}
    	}
    	for(scanf("%d%d%d%d%d",&T,&x,&a,&b,&c),a%=c,b%=c;T--;x=(1ll*x*a+b)%c+1)
    	{
    		sg+=g[x]+(x&1);sf+=f[x]+4*(x&1);
    		if(sg>=P) sg-=P;if(sf>=P) sf-=P;
    	}
    	printf("%d
    %d
    ",sg,sf);
    }
    
  • 相关阅读:
    最简单的UDP程序
    最简单的TCP程序
    一道面试题的分析
    JDK5新特性:可变参数方法
    文件IO流总结
    集合使用的总结
    双列集合Map的嵌套遍历
    集合HashSet的使用
    集合TreeSet的使用
    用LinkedList模拟Stack功能
  • 原文地址:https://www.cnblogs.com/CK6100LGEV2/p/9390392.html
Copyright © 2011-2022 走看看