河南萌新联赛2025第(四)场:L(数论+素数筛)

链接:https://ac.nowcoder.com/acm/contest/115184/L

题目要求

故障机器人探索完尖塔后得到了 n 个遗物,其中第 i 个遗物的价值是 \(a_i​\)。如果一个遗物的价值的因数个数是质数且不等于 2,那么故障机器人就认为这个遗物是一个完美遗物。故障机器人想要知道其拥有的完美遗物的价值之和是多少。

输入要求

第一行,输入一个整数 \(n (1≤n≤2⋅10^5)\),表示故障机器人所拥有遗物的数量。

第二行,输入 n 个整数 \(a_1​,a_2​,…,a_n​(1≤a_i​≤10^{12})\),其中 \(a_i​\) 表示故障机器人第 i 个遗物的价值。

输出要求

一行,一个整数,表示故障机器人所拥有的完美遗物的价值之和。

题目分析

①判断当前遗物是否为完美遗物(三个步骤如下):

1、计算该遗物价值的因数个数t;

2、该个数t为质数;

3、t≠2。

②将所有完美遗物的价值求和。

拆分步骤

①计算一个数的因数的个数,

已知数论里的一个基本结论:

  一个正整数 n 分解成素因数乘积后:

\[n=p_1^{a_1} \cdot p_2^{a_2} \cdot \cdots \cdot p_k^{a_k} \]

  那么它的因子个数是:

\[d(n) = (a_1 + 1)(a_2 + 1) \cdots (a_k + 1) \]

②由于我们需要判断其个数是否为质数,所以在此之前,我们需要写一个素数筛,对数组进行预处理方便后续的判断直接使用,这里我用的是经典的埃拉托色尼筛法。

代码实现思路

  • ①预处理素数数组(经典的埃拉托色尼筛法)

埃拉托色尼筛法模板

vector<bool> prim(int n)
	vector<bool> a(n+1,true);
	a[0]=a[1]=false;
	for(int i=2;i*i<=n;i++){
		if(a[i]){
			for(int j=i*i;j<=n;j+=i){
				a[j]=false;
			}
		}
	}
	return a;
}
vector<bool> a=prim(1e7);
  • ②将题目数据范围内的数预处理(直接算出该数是否是完美遗产)

因为$ a_i​+1≥2$,每一项 ≥2,并且至少有两项(k≥2)时,这个乘积一定不是质数。

只有当 n 是形如 \(p^q\) 的数(即只有一个素因子)时,才可能让 \(d(n)=q+1\) 是质数。

所以为了使 d(n) 是质数,n 必须是某个质数 p 的 q 次幂\((n=p^q)\),而且 q+1 也必须是质数(因为 d(n)=q+1)。

因此我们可以直接通过枚举,将所有符合条件的完美遗产数标记为真。

完整题解如下

#include <iostream>
#include <vector>
#include <cmath>
#define int long long

using namespace std;

const int N = 1e6;

vector<bool> is_prim;
vector<int> get_prim(int n){
    is_prim.assign(n+1, true);
    is_prim[0]=is_prim[1]=false;
    vector<int> prim;
    for(int i=2;i<n;i++){
        if(is_prim[i]){
            prim.push_back(i);
            for(int j=i*2;j<=n;j+=i){
                is_prim[j]= false;
            }
        }
    }
    return prim;
}
signed main() {
    int n;
    cin >> n;
    vector<int> prim= get_prim(N);
    vector<bool> judge(N+1, false);
    for(auto p:prim){
        int i=2;
        int x=p*p;
        while(x<N*N){
            if(i+1<is_prim.size()&&is_prim[i+1])
            {
                int q= sqrtl(x);
                if(q*q==x) judge[q]=true;
            }
            i++;
            x*=p;
        }
    }
    int numb,ans=0;
    for(int i=0;i<n;i++){
        cin>>numb;
        int m= sqrtl(numb);
        if(m*m==numb&&judge[m]){
            ans+=numb;
        }
    }
    cout<<ans<<endl;
    return 0;
}
posted @ 2025-08-06 21:34  芝士青瓜不拿铁  阅读(23)  评论(1)    收藏  举报