首页 > 其他分享 >洛谷题单指南-暴力枚举-P1036 [NOIP2002 普及组] 选数

洛谷题单指南-暴力枚举-P1036 [NOIP2002 普及组] 选数

时间:2024-01-31 14:33:13浏览次数:20  
标签:cnt NOIP2002 int 洛谷题 ++ 不选 P1036 二进制 lowbit

原题链接:https://www.luogu.com.cn/problem/P1036

题意解读:题目即要在n个数中,枚举出所有的子集,当子集中数字个数刚好为k时,求和,判断是否是素数。

解题思路:

方法一:二进制法

通过二进制法,可以枚举一个集合中所有元素“选”或者“不选”的情况,用二进制1表示选该元素,二进制0表示不选。

下面对样例数据进行模拟:

如上图,从上到下依次枚举0~24-1对应的二进制,根据二进制位的0/1来决定对应元素“选”或“不选”,

k=3的即二进制位有3个1的情况用绿色标识,求和后是素数的用红色标识。

因此对于一般的n个数,只需要枚举0~2n-1,判断每个数的二进制中1的个数是否为k,再针对每个二进制位是0或1决定选或不选对应元素。

这里就引出两个重要的二进制操作:

1、统计二进制有多少个1

首先,介绍一个关键的操作:lowbit,可以返回一个数的二进制中最后一个1所表示的整数

例如x=6,即二进制0110,lowbit(6) = 2,实现如下:

int lowbit(int x)
{
    return x & -x;
}

要计算一个数的二进制中有多少个1,只需要每次都减去这个数的lowbit,直到0为止,统计次数:

int count1(int x)
{
    int cnt = 0;
    while(x)
    {
        x -= lowbit(x);
        cnt++;
    }
}

2、二进制的某一位是0还是1

设整数i,要判断第j个(最低位j=0)二进制位是0还是1,只需要判断i >> j & 1是0还是1

100分代码-二进制法:

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

const int N = 25;

int n, k, ans;
int a[N];

//计算x的二进制中最后一个1所代表的整数,如11000回返回1000,也就是8
int lowbit(int x)
{
    return x & -x;
}

//计算x的二进制中有多少个1
int count1(int x)
{
    int cnt = 0;
    while(x)
    {
        x -= lowbit(x);
        cnt++;
    }
    return cnt;
}

//判断x是否是素数
bool isprime(int x)
{
    if(x < 2) return false;
    for(int i = 2; i * i <= x; i++)
    {
        if(x % i == 0) return false;
    }
    return true;
}

int main()
{
    cin >> n >> k;
    int pow2n = 1;
    for(int i = 0; i < n; i++)
    {
        cin >> a[i];
        pow2n *= 2; // 计算2^n 
    } 

    for(int i = 0; i < pow2n; i++)
    { 
        if(count1(i) == k) //如果整数i的二进制中1的个数==k
        {
            int sum = 0;
            for(int j = 0; j < n; j++) //遍历二进制的每一位
            {
                if(i >> j & 1) sum += a[j]; //i >> j & 1表示将i右移j位再和1求&,即判断i的第j位二进制是否是1,注意j=0表示第一位
            }
            if(isprime(sum)) ans++;
        }
    }

    cout << ans; 

    return 0;
}

方法二:DFS

n个数字,每个数字只有选或者不选两种情况,可以用一个数组保存选择的状态,1表示选,0表示不选,通过DFS来填充此数组即可。

100分代码-DFS:

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

const int N = 25;

int n, k, ans;
int a[N];

int tmp[N];

//判断x是否是素数
bool isprime(int x)
{
    if(x < 2) return false;
    for(int i = 2; i * i <= x; i++)
    {
        if(x % i == 0) return false;
    }
    return true;
}

void dfs(int level)
{
    if(level > n) // 找到一组选择
    {
        //判断是否有k个1
        int cnt = 0;
        for(int i = 1; i <= n; i++)
        {
            if(tmp[i] == 1) cnt++;
        }

        if(cnt != k) return;

        int sum = 0;
        for(int i = 1; i <= n; i++)
        {
            if(tmp[i] == 1) sum += a[i];
        }
        if(isprime(sum)) ans++;

        return;
    }
    for(int i = 0; i <= 1; i++)
    {
        tmp[level] = i;
        dfs(level + 1);
    }
}

int main()
{
    cin >> n >> k;
    for(int i = 1; i <= n; i++) cin >> a[i];

    dfs(1);
    cout << ans;

    return 0;
}

 

标签:cnt,NOIP2002,int,洛谷题,++,不选,P1036,二进制,lowbit
From: https://www.cnblogs.com/jcwy/p/17999205

相关文章

  • 洛谷题单指南-暴力枚举-P1618 三连击(升级版)
    原题链接:https://www.luogu.com.cn/problem/P1618题意解读:枚举所有三位数的组合情况,判断是否符合比例。解题思路:方法一:枚举第一个数根据题意,目的是寻找三个符合比例的三位数,可以直接枚举第一个,最小是123,最大是987设第一个数为x,三个数的比例关系是a:b:c设另外两个数为y,z那么,根......
  • 洛谷题单指南-暴力枚举-P2241 统计方形(数据加强版)
    原题链接:https://www.luogu.com.cn/problem/P2241题意解读:要在整个n*m区域计算正方形和长方形的个数,枚举法即可。解题思路:此题枚举的对象是矩形的高i和宽j,高的范围[1,n],宽的范围[1,m],然后计算在n*m区域内有多少个i*j,i==j即属于正方形,i!=j属于长方形。那么,问题就集中在了......
  • 洛谷题单指南-排序-P1012 [NOIP1998 提高组] 拼数
    原题链接:https://www.luogu.com.cn/problem/P1012题意解读:通过某种合理的排序方式,使得排序后的数字连在一起最大。解题思路:此题关键在于排序,对于两个数字,哪个数字应该排在前面呢?1、思考误区很容易想到,给定两个数abcd、xyz,先比较第一位a和x,谁大谁排前面,一直到c和z。再来看d,这......
  • 洛谷题单指南-排序-P1104 生日
    原题链接:https://www.luogu.com.cn/problem/P1104题意解读:将学生按照年龄由大到小排序,如果年龄相同,后输入的排在前面,输出排序后的学生姓名。解题思路:此题是一个排序常规题,年龄大排在前说明年、月、日越小越在前面,核心的排序思路如下:1、如果年份不同,按年份由小到大排序2、如果......
  • 洛谷题单指南-排序-P5143 攀爬者
    原题链接:https://www.luogu.com.cn/problem/P5143题意解读:给出一系列的点,按某种顺序经过所有点,计算距离。解题思路:如果小学生,可能对于三维坐标距离有些陌生,没关系,题目已经给出了计算公式,直接套公式即可,关键步骤如下:1、读取所有坐标点2、按高度值从小到大排序3、从头依次计算......
  • 洛谷题单指南-排序-P1068 [NOIP2009 普及组] 分数线划定
    原题链接:https://www.luogu.com.cn/problem/P1068题意解读:根据题意,用模拟法,求出分数线所在位置,然后计算分数线,最后输出结果即可。解题思路:1、分数线是按从大到小排名来设定,因此数据因为按照分数从大到小排序,如果分数相同,需要安装报名号从小到大排序2、计算分数线位置,主要是下......
  • 洛谷题单指南-排序-P1152 欢乐的跳
    原题链接:https://www.luogu.com.cn/problem/P1152题意解读:要判断相邻数差的绝对值是否覆盖1~n-1,只需遍历相邻两数之差,借助数组标记差的绝对值是否存在,然后遍历数组即可。解题思路:此题有两个注意点:1、数值要用longlong2、计算差值绝对值后,标记桶数组时,有可能导致越界,因为每个......
  • 洛谷题单指南-排序-P2676 [USACO07DEC] Bookshelf B
    原题链接:https://www.luogu.com.cn/problem/P2676题意解读:要使能够到书架顶的牛数量最少,优先选高的牛即可,直到总身高超过书架高度,简单的排序+贪心,下面给出代码。100分代码:#include<bits/stdc++.h>usingnamespacestd;constintN=20005;inth[N];intn,b;intmain......
  • 洛谷题单指南-排序-P1781 宇宙总统
    原题链接:https://www.luogu.com.cn/problem/P1781题意解读:题目思路非常简单,在n个投票数中选最大的,并记录其编号即可,由于投票数很大,无法直接用整形,需要通过string来进行数字比较。解题思路:本题的关键在于如何比较string数字的大小?在高精度减法时,需要判断两个数的大小,用大数减小......
  • 洛谷题解-[ABC286E] Souvenir
    https://www.luogu.com.cn/problem/AT_abc286_e题目描述NNN個の都市があり、いくつかの相異なる都市の間は一方通行の直行便によって移動することができます。どの直行便が存在するかはNNN個の長さNNNの文字列S1,S2,…,SNS_1,S_2,\ldots,S_NS1​,S2​,…,SN​......