GESP认证C++编程真题解析 | 202509 五级

编程题

P14073 数字选取

【题目来源】

洛谷:P14073 [GESP202509 五级] 数字选取 - 洛谷

【题目描述】

给定正整数 \(n\),现在有 \(1,2,…,n\) 共计 \(n\) 个整数。你需要从这 \(n\) 个整数中选取一些整数,使得所选取的整数中任意两个不同的整数均互质(也就是说,这两个整数的最大公因数为 \(1\))。请你最大化所选取整数的数量。

例如,当 \(n=9\) 时,可以选择 \(1,5,7,8,9\) 共计 \(5\) 个整数。可以验证不存在数量更多的选取整数的方案。

【输入】

一行,一个正整数 \(n\),表示给定的正整数。

【输出】

一行,一个正整数,表示所选取整数的最大数量。

【输入样例】

6

【输出样例】

4

【算法标签】

《洛谷 P14073 数字选取》 #数论# #素数判断,质数,筛法# #筛法# #GESP# #2025#

【代码详解】

#include <bits/stdc++.h>
using namespace std;

const int N = 100005;  // 定义最大范围

int n;                  // 输入的数字n
int isprime[N];         // 素数标记数组,isprime[i]存储i的最小质因数
map<int, int> mp;       // 用于记录已经统计过的质因数

int main()
{
    // 输入数字n
    cin >> n;

    // 埃拉托斯特尼筛法预处理最小质因数
    for (int i = 2; i < N; i++)
    {
        // 如果i是素数,则标记其倍数
        if (isprime[i] == 0)
        {
            for (int j = i + i; j < N; j += i)
            {
                // 如果j还没有被标记过,则记录其最小质因数
                if (isprime[j] == 0)
                {
                    isprime[j] = i;
                }
            }
        }
    }

    // 统计1到n范围内的素数个数
    int cnt = 0;
    for (int i = 1; i <= n; i++)
    {
        if (isprime[i] == 0)
        {
            cnt++;
        }
    }

    // 统计1到n范围内合数的不同质因数个数
    for (int i = 1; i <= n; i++)
    {
        // 如果是素数或者已经统计过该质因数,则跳过
        if (isprime[i] == 0 || mp[isprime[i]] == 1)
        {
            continue;
        }
      
        // 标记该质因数已经统计过
        mp[isprime[i]] = 1;
        cnt++;
    }

    // 输出结果:素数个数 + 不同质因数个数
    cout << cnt << endl;

    return 0;
}

【运行结果】

6
4

P14074 有趣的数字和

【题目来源】

洛谷:P14074 [GESP202509 五级] 有趣的数字和 - 洛谷

【题目描述】

如果一个正整数的二进制表示包含奇数个 \(1\),那么小 A 就会认为这个正整数是有趣的。

例如,\(7\) 的二进制表示为 \((111)_2\),包含 \(1\) 的个数为 \(3\) 个,所以 \(7\) 是有趣的。但是 \(9=(1001)_2\) 包含 \(2\)\(1\),所以 \(9\) 不是有趣的。

给定正整数 \(l,r\),请你统计满足 \(l≤n≤r\) 的有趣的整数 \(n\) 之和。

【输入】

一行,两个正整数 \(l,r\),表示给定的正整数。

【输出】

一行,一个正整数,表示 \(l,r\) 之间有趣的整数之和。

【输入样例】

3 8

【输出样例】

19

【算法标签】

《洛谷 P14074 有趣的数字和》 #GESP# #2025#

【代码详解】

#include <bits/stdc++.h>
using namespace std;

#define int long long  // 使用长整型防止溢出

int l, r;              // 输入的数字区间[l, r]
int ans;               // 存储计算结果
int b;                 // 计算第b个区间
int v[9] = {0, 1, 3, 3, 7, 7, 7, 14, 22};  // 预计算的小数值结果(1-8的答案)

/**
 * 计算数字x的二进制表示中1的个数(汉明重量)
 * @param x 要计算的数字
 * @return 二进制中1的个数
 */
int check(int x)
{
    int cnt = 0;  // 计数器,记录1的个数
    while (x > 0)
    {
        if (x & 1)  // 检查最低位是否为1
            cnt++;   // 如果是1,计数器加1
        x = x >> 1;  // 右移一位,相当于除以2
    }
    return cnt;
}

/**
 * 计算从1到x的所有满足条件的数的和
 * @param x 上界
 * @return 计算结果
 */
int f(int x)
{
    // 如果x小于等于8,直接返回预计算的结果
    if (x <= 8)
        return v[x];
  
    // 计算区间个数(默认向下取整)
    b = x / 4;
  
    // 计算从第1到第b个区间的总和
    ans = (b * b) * 4 - b;
  
    // 计算剩余部分的值(从b*4到x)
    for (int i = (b * 4); i <= x; i++)
    {
        // 如果二进制1的个数为奇数,则累加
        if (check(i) % 2)
            ans += i;
    }
  
    return ans;
}

signed main()
{
    // 输入区间范围
    cin >> l >> r;
  
    // 输出区间内满足条件的数的和(前缀和思想)
    cout << f(r) - f(l - 1);
  
    return 0;
}

【运行结果】

3 8
19
posted @ 2026-02-15 16:33  团爸讲算法  阅读(3)  评论(0)    收藏  举报