zoukankan      html  css  js  c++  java
  • 求1到n的质数个数和O(n)

    也许更好的阅读体验
    (mathcal{AIM})

    我们知道:
    对于一个合数(x)(x=p^{a_1}_1*p^{a_2}_2*...*p^{a_n}_n)
    现在给出一个(n)(xin[1,n]),所有(x)分解出的(p)的幂数和
    例如
    (n=12)
    (2=2^1)
    (3=3^1)
    (4=2^2)
    (5=5^1)
    (6=2^1*3^1)
    (7=7^1)
    (8=2^3)
    (9=3^2)
    (10=2^1*5^1)
    (11=11^1)
    (12=2^2*3^1)

    数字 个数
    2 10
    3 5
    5 2
    7 1
    11 1

    (mathcal{Resolvent})

    对于一个合数(x)(x=p^{a_1}_1*p^{a_2}_2*...*p^{a_n}_n)

    (O(nsqrt n))

    这是最简单的想法,先记录哪些数是质数,再把(n)以内所有的数分解掉

    int cnt;
    int prime[maxn],num[maxn];//prime -> 求出来的质数   num -> 每个数出现个数
    bool vis[maxn];//欧拉筛里看其是否是质数
    ols(n);//这是欧拉筛
    for (int i=1;i<=n;++i)
    	for (int j=1;j*j<=i&&j<=cnt;++j){
    		int t=i;
    		while (t%prime[j]==0)	++num[prime[j]],t/=prime[j];
    	}
    

    (O(nlog_2n))

    考虑可不可以直接对整体求
    这个方法对一些其他题也很有用

    int cnt;
    int prime[maxn],num[maxn];
    bool vis[maxn];
    ols(n);
    for (int i=1;i<=cnt;++i){
    	int t=prime[i],mi=1;//mi -> mi次幂
    	while (t<=n){
    		num[prime[i]]+=n/t*mi;
    		t*=prime[i],++mi;
    	}
    }
    

    (O(n))

    对一个数 (x)
    (x/p_1)显然是比(x)小的,若我们知道(x/p_1)的答案,那么(x)的贡献就是(x/p_1)的贡献加上对(p_1)的一个贡献
    但我们把(x/p_1)的答案存下来只会增加复杂度
    于是我们可以反过来循环,(x)先对(p_1)加一个贡献,之后我们就可以认为多了一个(x/p_1)
    计算(x/p_1)时答案就会多一,显然我们可以一直传递下去,这样每个数只用把自己最小质因子的贡献算出即可

    int cnt;
    int prime[maxn],num[maxn],come[maxn];//come[i] -> i的最小质因子
    bool vis[maxn];
    ols(n);
    for (int i=n;i>=2;--i){
    	if (vis[i]){//如果是个合数
    		num[come[i]]+=num[i];//最小质因子加上当前这个数要计算次数
    		num[i/come[i]]+=num[i];//加上这个数需计算次数
    		num[i]=0;//当前这个数没了
    	}
    }
    
    
    
  • 相关阅读:
    2101 可达性统计
    POJ1179 Polygon
    POJ1015 Jury Compromise
    读入输出优化
    队列优化dijsktra(SPFA)的玄学优化
    5104 I-country
    CH5102 Mobile Service
    P1005 矩阵取数游戏
    (模板)线段树2
    POJ3666 Making the Grade
  • 原文地址:https://www.cnblogs.com/Morning-Glory/p/10961055.html
Copyright © 2011-2022 走看看