1 条题解

  • 0
    @ 2024-10-7 13:20:55

    解题思路: 一、先用筛法生成质数列表prime[],以及f[i]标记(含义:i是不是合数),并且生成质数索引p_idx[i](含义:i是第几个质数,如果i自己不是质数则它前面的质数是第几个),方便后面快速统计区间内的质数个数,R的索引减L的索引即可。 二、同时每找到一个新的质数,都与已找到的质数(prime[]中的所有含刚找到的质数)相乘,生成z[t]标记(t是不是两个质数的积)。 三、最后做一个循环,根据质数积标记z[t],生成质数积索引z_idx[i](含义:i是第几个质数积,如果i自己不是质数积则它前面的质数积是第几个)。 四、读入各组区间数据,根据L、R的p_idx索引和z_idx索引值直接推算出区间内共有多少个小X喜欢的数。计算时要注意区分L是不是质数(或质数积)的情形。 五、结论:曾经想过用筛法生成质数列表(6.6万)、质数积列表(190万)后, 用二分法查询起止L、R在这两个列表的位置。但似乎比较耗时,一来质数积列表生成时是无序的,要先排序, 时间复杂度190万log(190万)=310^7;二来有10^5组数据,每组要对两个列表各查2次,时间复杂度10^5 * 2* (log(6.6万)+log(190万))=6*10^6。 所以最后还是用了提前生成索引的方法,质数列表索引不用额外增加时间复杂度,生成质数积列表索引增加10^7。还是比较划算的。 更简单做法是线性筛。

    #include <bits/stdc++.h>
    using namespace std;
    const int N=1e7+2; 
    int q,l,r,ma=N,pcnt,zcnt;
    bool f[N],z[N];//f[i]==1:i是合数,z[i]==1:i是两个质数的积 
    int prime[N],z_idx[N],p_idx[N];//p_idx某个质数是第几个 
    int main(){
    	for(int i=2;i<=ma;i++){		
    		if(f[i]==0){
    			prime[pcnt++]=i;
    			p_idx[i]=pcnt;			
    			for(long long j=(long long)i*i;j<=ma;j+=i)	f[j]=1;				
    			for(int k=0;k<pcnt;k++){//新质数乘以已知质数(含自己),加入到zhi质数积数组 
    				long long t=(long long)i*prime[k];
    				if(t<=ma) z[t]=1;
    				else break;
    			}			
    		}
    		p_idx[i]=pcnt;//i是第几个质数,如果i自己不是质数则i前面的质数是第几个 		
    	}
    	for(int i=2;i<=ma;i++){ //生成z的索引 
    		if(z[i]) zcnt++; 
    		z_idx[i]=zcnt;
    	}	
    	cin>>q;		
    	for(int i=0;i<q;i++){
    		scanf("%d%d",&l,&r);
    		if(l<2)l=2;
    		printf("%d\n",p_idx[r]-p_idx[l]+!f[l]+z_idx[r]-z_idx[l]+z[l]);
    	}
    }
    
    • 1

    信息

    ID
    2670
    时间
    1000ms
    内存
    256MiB
    难度
    5
    标签
    递交数
    96
    已通过
    38
    上传者