蓝桥杯备赛:Day5-P1036 选数

📚 算法笔记:P1036 NOIP 2002 普及组 选数

1. 题目描述

P1036 [NOIP 2002 普及组 选数 - 洛谷](https://www.luogu.com.cn/problem/P1036)

从 n n n 个整数中任选 k k k 个数相加,统计有多少种选法的质数

  • 数据范围: n ≤ 20 , k < n n \le 20, k < n n≤20,k<n,每个整数 < 5 × 10 6 < 5 \times 10^6 <5×106。

2. 核心代码 (C++ AC版本)

c++ 复制代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

ll a[25];        // 存储输入的 n 个数
int N, K;
ll ans = 0;      // 计数器:符合条件的质数和个数

// 质数判定:O(sqrt(sum))
bool is_prime(int n) 
{
    if (n < 2) return false;
    for (int i = 2; i * i <= n; i++) 
    { 
        if (n % i == 0) return false;
    }
    return true;
}

// DFS 组合模型
// position: 当前选到了第几个数
// sum:      当前已选数字的累加和
// start:    搜索起点,保证下标单调递增
void dfs(int position, ll sum, int start)
{
    // 1. 递归出口:选够了 K 个数
    if(position > K)
    {
        if(is_prime(sum)) ans++;
        return; 
    }
    
    // 2. 组合模型核心:从 start 开始往后选,不回头
    for(int i = start; i <= N; i++)
    {
        // 隐式回溯:sum + a[i] 作为参数传递,无需手动撤销
        dfs(position + 1, sum + a[i], i + 1);
    }
}

void solve()
{
    if(!(cin >> N >> K)) return;
    for (int i = 1; i <= N; i++) cin >> a[i];
    
    ans = 0;
    dfs(1, 0, 1);
    cout << ans << endl;
}

int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0); cout.tie(0);
    
    int _ = 1;
    while(_--) solve();
    return 0;
}

3. 核心考点与注意事项

  • 组合模型 (Combination) :与全排列不同,组合不计较顺序。通过引入 start 参数,强制让选取的下标单调递增 ( i → i + 1 i \rightarrow i+1 i→i+1),从而物理隔绝了重复排列(如选了 1 , 2 1,2 1,2 就不会再选 2 , 1 2,1 2,1)。
  • 隐式回溯 :在 dfs(position + 1, sum + a[i], i + 1) 中,sum + a[i] 的结果直接传给下一层。当递归返回时,本层的 sum 值并没有改变,因此不需要used 数组那样手动执行 sum -= a[i]
  • 质数优化 :使用 i * i <= n 进行判定,时间复杂度为 O ( N ) O(\sqrt{N}) O(N ),是应对高频调用的标准写法。
相关推荐
王老师青少年编程38 分钟前
信奥赛C++提高组csp-s之搜索进阶(迭代加深IDDFS)
c++·csp·信奥赛·csp-s·提高组·iddfs·埃及分数
liulilittle1 小时前
我从 BBRv1 到 KCC 的思考
网络·c++·tcp/ip·计算机网络·tcp·bbr·通信
落羽的落羽1 小时前
【项目】JsonRpc框架——开发实现1(细节功能、字段定义、抽象层、具象层)
linux·服务器·网络·c++·人工智能·算法·机器学习
handler011 小时前
【算法】并查集(普通/扩展/带权)模板与例题
数据结构·c++·笔记·算法·c·图论·查并集
繁星蓝雨2 小时前
C++中对比pragma once和ifndef的使用区别
开发语言·c++·ifndef·头文件·pragma once
.千余2 小时前
【C++】C++手写Vector容器:从底层源码模拟实现
开发语言·c++·经验分享·笔记·学习
a诠释淡然2 小时前
C++ vs Rust:哪个更适合你的下一个项目?
开发语言·c++·rust
小小de风呀2 小时前
de风——【从零开始学C++】(十二):stack和queue的基本使用和模拟实现
开发语言·c++
汉克老师2 小时前
GESP6级C++考试语法知识(五十三、动态规划----背包问题(六、分组背包)
c++·动态规划·背包问题·gesp6级·gesp六级·分组背
雪度娃娃3 小时前
转向现代C++——保证const成员函数的线程安全性
开发语言·c++