容斥原理——數學知識

Annabel_CM發表於2020-11-28

容斥原理

可以描述如下:

要計算幾個集合並集的大小,我們要先將所有單個集合的大小計算出來,然後減去所有兩個集合相交的部分,再加回所有三個集合相交的部分,再減去所有四個集合相交的部分,依此類推,一直計算到所有集合相交的部分。

在這裡插入圖片描述

用維恩圖來表示集合A、B和C:

在這裡插入圖片描述
在這裡插入圖片描述

經典例題

AcWing 890. 能被整除的數
給定一個整數n和m個不同的質數p1,p2,…,pm。

請你求出1~n中能被p1,p2,…,pm中的至少一個數整除的整數有多少個。

輸入格式
第一行包含整數n和m。

第二行包含m個質數。

輸出格式
輸出一個整數,表示滿足條件的整數的個數。

資料範圍
1≤m≤16,
1≤n,pi≤109
輸入樣例:

10 2
2 3

輸出樣例:

7

在這裡插入圖片描述

#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;

    for (int i = 0; i < m; i ++ ) cin >> p[i];

    int res = 0;
    for (int i = 1; i < 1 << m; i ++ ) //  i<1<<m   組合數  2^m-1 
    {
        int t = 1, s = 0;//s用來記錄這種方案,選擇的數的個數,從而判斷應該加還是減;t存累乘的結果
        for (int j = 0; j < m; j ++ )//遍歷二進位制的每一位
            if (i >> j & 1)//判斷二進位制第j位是否存在
            {
                if ((LL)t * p[j] > n)//這裡要加long 否則會溢位
                {
                    t = -1;
                    break;
                }
                t *= p[j];
                s ++ ;
            }//為這種方案求出一個總乘積t

        if (t != -1)
        {
            if (s % 2) res += n / t;//奇數個數,說明要加
            else res -= n / t;//偶數個數,說明要減
        }
    }

    cout << res << endl;

    return 0;
}

相關文章