java---容斥原理---能被整除的数(每日一道算法2022.9.30)

注意事项:
涉及到位运算:java—位运算(二进制中1的个数

题目:
给定一个整数 n 和 m 个不同的质数 p1,p2,…,pm
请你求出 1∼n 中能被 p1,p2,…,pm 中的至少一个数整除的整数有多少个

第一行包含整数 n 和 m
第二行包含 m 个质数

输入:
10 2
2 3
输出:
7
public class 容斥原理_能被整除的数 {
    public static int N = 20;
    public static int[] p = new int[N];

    public static void main(String[] args) {
        //读入n, m和m个质数
        Scanner in = new Scanner(System.in);
        int n = in.nextInt(), m = in.nextInt();
        for (int i = 0; i<m; i++) p[i] = in.nextInt();

        int res = 0;
        //注意这里是i是1起始,1左移m位就是2的m次方,我们总共枚举(2^m - 1)次, 这里是根据容斥原理公式得知
        //t表示所有质数的乘积, count表示当前i的二进制包含几个1,也就是当前选法有几个集合
        for (int i = 1; i < (1<<m); i++) {
            int t = 1, count = 0;

            //这里是用位运算来对比i的二进制的每一位,得到当前i的二进制中有几个1,也就是得到当前选法使用了几个集合
            for (int j = 0; j < m; j++) {
                if (((i >> j) & 1) == 1) {
                    if ((long)t * p[j] > n) {   //如果t*p[j] > n,说明1∼n中的数不能被p整除,那就不用继续算了
                        t = -1;
                        break;
                    }

                    count++;
                    t *= p[j];      //将该质数乘到t中
                }
            }

            //根据n/p能得到1~n中所有p的倍数的个数,那么扩展一下,n/(p1*p2*...*pk)就可以得到1~n中同时是p1,p2...pk的倍数的个数 (注意是整除)
            //这里根据容斥原理公式: 奇数个集合是加,偶数个集合是减
            if (t != -1) {
                if (count % 2 != 0) res += n / t;
                else res -= n / t;
            }
        }

        System.out.println(res);
    }
}

思路:
容斥原理公式:
⋃ i = 1 m S i = S 1 + S 2 + … + S m − ( S 1 ⋂ S 2 + S 1 ⋂ S 3 + … + S m − 1 ⋂ S m ) + ( S 1 ⋂ S 2 ⋂ S 3 + … + S m − 2 ⋂ S m − 1 ⋂ S m ) + … + ( − 1 ) m − 1 ( ⋂ i = 1 m S ) \bigcup_{i=1}^{m} S_i = S_1 + S_2 + \ldots + S_m - (S_1 \bigcap S_2 + S_1 \bigcap S_3 +\ldots + S_{m-1} \bigcap S_m)+ (S_1 \bigcap S_2 \bigcap S_3 +\ldots + S_{m-2} \bigcap S_{m-1} \bigcap S_m) + \ldots + (-1)^{m - 1} (\bigcap_{i=1}^{m}S) i=1mSi=S1+S2++Sm(S1S2+S1S3++Sm1Sm)+(S1S2S3++Sm2Sm1Sm)++(1)m1(i=1mS)

容斥原理公式的直观应用(韦恩图求三个圆的不重叠面积):
请添加图片描述
一些证明:
请添加图片描述
请添加图片描述

以题目为栗子:
S 1 = { 2 , 4 , 6 , 8 , 10 } , S 2 = { 3 , 6 , 9 } , S 1 ⋂ S 2 = { 6 } , 故 S 1 ⋃ S 2 = { 2 , 3 , 4 , 6 , 8 , 9 , 10 } S_1 = \lbrace 2,4,6,8,10 \rbrace , S_2 = \lbrace 3,6,9 \rbrace, S_1 \bigcap S_2 = \lbrace 6 \rbrace, 故S_1 \bigcup S_2 = \lbrace 2,3,4,6,8,9,10 \rbrace S1={2,4,6,8,10},S2={3,6,9},S1S2={6},S1S2={2,3,4,6,8,9,10}

又是后半夜更新的一天~10月1号了哎,大家国庆假期快乐

声明:
算法思路来源为y总,详细请见https://www.acwing.com/
本文仅用作学习记录和交流

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值