容斥原理学习笔记

容斥原理

1. 容斥原理式子

\[|S_1 \cup S_2 \cup S_3 \cdots \cup S_n| = \sum_{1<i<n}|S_i| - \sum_{i<i<j<m}|S_i \cap S_j| + \sum_{1<i<j<k<m}|S_i \cap S_j \cap S_k| - \cdots + (-1)^{n-1}|S_i \cap S_j \cap S_k \cap \cdots \cap S_n| \]

2. 一个不太严谨的证明

    我们在\(|S_1 \cup S_2 \cup S_3 \cdots \cup S_n|\)中设一个元素为\(x\)\(x\)在所有\(S\)集合中出现了\(k\)\((1<k<n)\)。则\(x\)\(\sum_{1<i<n}|S_i|\)会被加\(k\)次,即\(C^{1}_{k}\),在\(\sum_{i<i<j<m}|S_i \cap S_j|\)中会被减去\(C^{2}_{k}\)次,以此我们可以得到以下柿子:

\[C^{1}_{k} - C^{2}_{k} + C^{3}_{k} - \cdots + (-1)^{k-1}C^{k}_{k} \]

\(\sum^{n}_{i}C^{i}_{n}\)可知这个式子一定是等于\(1\)的,即\(x\)\(|S_1 \cup S_2 \cup S_3 \cdots \cup S_n|\)中只会出现一次。

3. 一道简单的例题:AcWing890.能被整除的数

题比较简单,容斥+状压

#include<bits/stdc++.h>
using namespace std;
int p[1000];
int main()
{
    int n,m;
    cin>>n>>m;
    for(int i=1;i<=m;i++)
    {
        cin>>p[i];
    }
    int res=0;
    for(int i=1;i<=(1<<m)-1;i++)
    {
        int t=1,cnt=0;
        for(int j=0;j<m;j++)
        {
            if(i>>j&1)
            {
                cnt++;
                if((long long)t*p[j+1]>n)
                {
                    t=-1;
                    break;
                }
                t*=p[j+1];
            }
        }
        if(t!=-1)
        {
            if(cnt%2) res+=n/t;
            else res-=n/t;
        }
    }
    cout<<res;
    return 0;
}
posted @ 2020-12-14 14:05  面包络合物  阅读(96)  评论(0编辑  收藏  举报