• pxp


    Time Limit: 2000 ms Memory Limit: 512 MB

    Description

      给定 (n), 求(sumlimits_{p,q∈primes}[pq≤n])
      (其中 primes 表示全体质数组成的集合)
      (其中 [expression] 当 expression 为真时值为 (1), 否则为 (0))

    Input

      一行一个数 (n)

    Output

      一行一个数表示答案

    Sample Input

    sample 1:
    1
    sample 2:
    5
    sample 3:
    10
    

    Sample Output

    sample 1:
    0
    sample 2:
    1
    sample 3:
    6
    

    HINT

      对于 20% 的数据, (1≤n≤10^8)
      对于 100% 的数据 , (1≤n≤10^{11})


    Solution

      (所以为什么学长强行出了一道科普性质的题啊qwq被科普到了qwq)

    • 20%

      线性筛爆搞一下就好了

    • 100%

      于是乎这里就科普了一种十分神秘的筛法了qwq

      首先先想想怎么去求我们的(ans)

      用(pcnt(i))表示小于等于(i)的素数的个数,用(cnt)表示小于等于(sqrt{n})的素数的个数,(P)为素数列表,那么

    [ans=(2*sumlimits_{i=1}^{cnt}pcnt(lfloor frac{n}{P_i} floor)-i)+cnt ]

      具体一点的话就是,如果两个素数(p)(q)的乘积小于等于(n),那么这两个素数中必定有一个小于等于(sqrt{n}),所以我们只要枚举小于等于(sqrt{n})的那个素数然后把(pcnt(lfloorfrac{n}{p} floor))累加起来最后乘个(2)就好了,然而由于这样在枚举的时候会重复,所以我们钦定每个素数只算与大于它的素数相乘的贡献,因此要减掉(i)(也就是前面小于p的数中有多少个素数),最后再加上自己乘自己的(cnt)种情况就好了

      

      那么现在的问题就是要求(pcnt(i)),我们先不考虑空间的问题

      考虑把(pcnt(i))筛出来,大致思路如下:

        1.去掉既不是合数也不是素数的(1)

        2.去掉小于等于i的合数

      去掉(1)的话就是初始化(pcnt(i)=i-1),这个比较好搞

      去掉合数的话,我们考虑用每个素数(p)去筛掉(i>p)(pcnt(i))中的一些数

      考虑每个(p)能够筛掉的部分,应该是形如(p*k (kin [2,lfloor frac{i}{p} floor]))

      而因为我们是从小到大一直用不同的素数去筛,所以到用(p)筛的时候,(pcnt(i))中包含的数的最小质因子应该是大于等于(p)的,所以(p)能够筛掉的部分,实际上应该是形如(的最小质因子p*k (k的最小质因子>=p)),也就是说实际上真正能够被(p)筛掉数的(i)应该满足:(i>=p^2)

      再考虑一下当前那些还没有被完全筛成正确答案的(pcnt(x))具有什么性质:

        1.(x>p)

        2.(pcnt(x))由两部分组成,对于小于(p)的部分,所有的合数已经被筛完了,而大于(p)的部分,仅有最小 质因子(>=p)的数

        也就是说(pcnt(x))=小于(p)的素数个数 + (p)(x)中最小质因子(>=p)的数的个数
        

      然后回去看对于(pcnt(i))来说(p)能够筛掉的数,我们会发现其实上面提到的(k)的个数其实就是(pcnt(lfloor frac{i}{p} floor)-pcnt(p-1))

      具体一点的话就是:

      (因为只有对于(i>=p^2)(pcnt(i))(p)才能筛掉数,所以接下来讨论的(pcnt(i))都默认(i>=p^2)

      因为(i>=p^2),所以(lfloor frac{i}{p} floor>=p)

      对于大于的情况,(pcnt(lfloor frac{i}{p} floor)=小于p的素数个数+p到lfloor frac{i}{p} floor中的最小质因子>=p的数的个数)
      那么(k)的个数就是(pcnt(lfloor frac{i}{p} floor)-pcnt(p-1))(pcnt(p-1))已经被筛好了)

      对于等于的情况,能去掉的只有(p^2),此时(pcnt(lfloor frac{i}{p} floor)=pcnt(p)), 相减一下得到(1),也是成立的

      

      综上,筛掉合数我们要做的就是:

      用每个素数去筛,对于每个(i>=p^2),从(pcnt(i))减去(pcnt(lfloor frac{i}{p} floor)-pcnt(p-1))即可

      至于素数,其实也不用预处理什么的,只要判断(pcnt(i))(pcnt(i-1))是否相等即可,不等说明(i)是素数

      

      然而现在的问题是,空间开不了这么大啊

      我们考虑将(pcnt(i))分成两部分:

      (p1(i)=pcnt(i))(p2(i)=pcnt(lfloor frac{n}{i} floor))(iin[1,sqrt{n}])

      (p1(i))的话直接算就好了

      (p2(i))的话,考虑用(p)来筛的情况,我们套回上面的式子稍微化一下得到:

    [egin{aligned} p2(i)&=pcnt(lfloor frac{n}{i} floor)\ &=pcnt(lfloor frac{n}{i} floor)-(pcnt(lfloor frac{lfloor frac{n}{i} floor}{p} floor)-pcnt(p-1))\ &=pcnt(lfloor frac{n}{i} floor)-(pcnt(lfloor frac{n}{i*p} floor))-pcnt(p-1))\ end{aligned} ]

      考虑(lfloor frac{n}{i*p} floor)的取值,如果说这个值小于等于(sqrt{n})那么(pcnt(lfloor frac{n}{i*p} floor)=p1(lfloor frac{n}{i*p} floor)),否则(pcnt(lfloor frac{n}{i*p} floor)=p2(i*p))

      那就直接在枚举的时候判断一下就好了

      注意最后统计(ans)的时候因为我们要调用的是(()pcnt(lfloor frac{n}{P_i} floor)(lfloor frac{n}{P_i} floor>=sqrt{n})),所以应该是用(p2(lfloor frac{n}{lfloor frac{n}{P_i} floor} floor))
      

      代码大概长这个样子

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #define ll long long 
    using namespace std;
    const int MAXN=1e6+10;
    ll p1[MAXN],p2[MAXN],lis[MAXN];
    ll n,m,sq,ans,cnt;
    
    int main(){
    #ifndef ONLINE_JUDGE
    	freopen("a.in","r",stdin);
    #endif
    	scanf("%lld",&n);
    	sq=sqrt(n);
    	for (int p=2;p<=sq;++p) p2[p]=n/p-1,p1[p]=p-1;
    	for (ll p=2;p<=sq;++p)
    		if (p1[p]!=p1[p-1]){
    			lis[++cnt]=p;
    			for (ll i=1;i<=sq&&1LL*p*p<=n/i;++i){
    				if (n/(1LL*p*i)>sq)
    					p2[i]-=p2[p*i]-p1[p-1];
    				else
    					p2[i]-=p1[n/(1LL*p*i)]-p1[p-1];
    			}
    			for (int i=sq;i>=p*p;--i){
    				p1[i]-=p1[i/p]-p1[p-1];
    			}
    		}
    	ans=0;
    	for (int i=1;i<=cnt;++i)
    		ans+=p2[n/(n/lis[i])]-i;
    	printf("%lld
    ",ans*2+cnt);
    }
    
    
  • 相关阅读:
    SpringBoot第四集:整合JDBC和JPA(2020最新最易懂)
    SpringBoot第六集:整合监听器/过滤器和拦截器(2020最新最易懂)
    SpringBoot第八集:静态资源与首页定制(2020最新最易懂)
    TM1621断码液晶驱动IC的原理、驱动代码
    代码编码格式批量转换工具
    LAN8720 调试笔记
    C# 读取电脑CPU、主板、硬盘序列号等信息
    C# 读取串口设备列表
    C# 窗口全屏、置顶、获取焦点
    STM32 获取系统时钟频率
  • 原文地址:https://www.cnblogs.com/yoyoball/p/8780223.html
Copyright © 2020-2023  润新知