当前位置: 首页 > article >正文

容斥原理 C++

题目

图源ACWING

解题思路

什么是容斥原理
在这里插入图片描述
具体到题目中
S1代表1到n中能被质数p1整除的数的集合,而|S1|代表1~n中能被质数p1整除的数的数量;

则题目所求结果:
res = | S1 U S2 U S3 … U Sm | = |S1| + |S2| + |S3| + … + |Sm| (C(m, 1)个数) - (|S1 ∩ S2| + |S1 ∩ S3| + …) (C(m, 2)个数) + … + (-1)n-1(S1∩S2∩S3…∩Sm) (C(m, m) 个数)

同时C(m, 0) + C(m ,1) + C(m, 2) + C(m , 3) + … C(m, m) = 2m(相当于一个球袋中拿走任意数量的球的方案量, 即每个球都只有拿走与不拿走两个选项,总方案量就是2m)

所以,总循环次数就是2m - 1,即可得到答案res;

具体实现方法
图源https://www.acwing.com/solution/content/29702/

代码实现

#include <iostream>
#include <algorithm>

using namespace std;

typedef long long LL;

const int N = 20;

int p[N];


int main()
{
    int n, m;
    cin >> n >> m;

    // 用p数组存储m个质数
    for (int i = 0; i < m; i ++ ) cin >> p[i];

    int res = 0;
    // 每一个i代表一种可能的取法,最外层的循环遍历置2的m次方后,可以取完所有的取法
    // 从1开始枚举,枚举到1 << m(左移m位。左移一位相当于乘2,右移一位相当于除2),即2的m次方;
    for (int i = 1; i < 1 << m ; i ++ )//等同于i < 2^m^
    {
        // t代表当前所有质数的乘积,s代表什么当前选法包含几个集合
        int t = 1, s = 0;
        // 枚举m个质数,依次计算容斥原理的公式
        for (int j = 0; j < m; j ++ ){
            // i右移j位与上1,即如果当前位是1的话
            //>>的优先级大于&,所以是先>>再&!
            if (i >> j & 1)
            {
                if ((LL)t * p[j] > n)//主要原因是为了防止爆long long,导致出现错误答案!!!
                {
                    t = -1;
                    break; // break的作用域是跳出整个循环
                }
                // 将该质数乘到t中
                t *= p[j];
                // s表示当前选法中有多少个集合
                s ++ ;
            }
        }
        // 带入公式求解一个S
        // 如果t不等于-1(-1是给定的flag值)
        if (t != -1)
        {
        //根据公式,如果s是偶数要减去,是奇数要加上
            if (s % 2) res += n / t;
            else res -= n / t;
        }
    }

    cout << res << endl;

    return 0;
}

具体代码块分析

假设m = 4的情况下:

 // 每一个i代表一种可能的取法,最外层的循环遍历置2的m次方后,可以取完所有的取法
    for (int i = 1; i < 1 << m ; i ++ )//等同于i < 2^m^

这段代码等同于:i = 0001; i < 10000; i ++ (二进制);
而不同的i代表选择了不同的集合:
比如i = 0101时, 选择了S1和S3这两个集合。
继续带入下面的代码:

        for (int j = 0; j < m; j ++ ){
            // i右移j位与上1,即如果当前位是1的话
            //>>的优先级大于&,所以是先>>再&!
            if (i >> j & 1)
            {
                if ((LL)t * p[j] > n)//主要原因是为了防止爆long long 的数据范围,导致出现错误!!!
                {
                    t = -1;
                    break;
                }
                // 将该质数乘到t中
                t *= p[j];
                // s表示当前选法中有多少个集合
                s ++ ;
            }
        }
        // 带入公式求解一个S
        // 如果t不等于-1(-1是给定的flag值)
        if (t != -1)
        {
        //根据公式,如果s是偶数要减去,是奇数要加上
            if (s % 2) res += n / t;
            else res -= n / t;
        }

实际上计算的是|S1∩S3|的值;


http://www.kler.cn/news/361836.html

相关文章:

  • 玫瑰花HTML源码
  • 搭建微信AI机器人
  • Qt信号和槽记录
  • ENSP环回路由的配置
  • 电影院订票选座小程序ssm+论文源码调试讲解
  • maven创建父子项目
  • 双一流大学“一网通办”系统的国产数据库实践
  • maven jar包二进制文件 invalid stream header: EFBFBDEF 的错误
  • 智慧停车及可视化管理解决方案;停车场电子地图应用方案;地下停车场如何实现反向寻车,车位引导等功能;智慧停车实时导航解决方案
  • 【ODSS】An Open Dataset of Synthetic Speech
  • WebRTC音频 03 - 实时通信框架
  • NeRF三维重建—神经辐射场Neural Radiance Field(二)体渲染相关
  • 5G智能终端:低空经济崛起的隐形翅膀!
  • 销售出库单同步——从旺店通到金蝶云星辰V2的成功案例
  • YOLOV11改进系列指南
  • pandas 数据分析实战
  • .net framework 3.5sp1如何开启?
  • SpringBoot3 + OpenAPI3规范 快速整合
  • el-table 表格设置必填项
  • Python实现股票自动交易:步骤、要点与注意事项有哪些?
  • spring boot实现不停机更新
  • ford面试准备
  • 传输层协议——TCP、UDP
  • 正在等待缓存锁:无法获得锁 /var/lib/dpkg/lock-frontend。锁正由进程 5427(unattended-upgr)持有
  • PPT自动化:如何判断PPT中的shape类型(python-pptx中常见shape类型及其代码速查表)
  • C++进阶之路:日期类的实现、const成员(类与对象_中篇)