容斥原理

容斥原理

  • 内容
    用于解决多个有相交情况的集合的并集,例如三个集合的情形:输入图片说明

对于n个集合的交集有公式:|S1S2S3Sn|=(|S1|+|S2|+|S3|++|Sn|)(|S1S2|+|S1S3|++|Sn1Sn|+(|S1S2S3|+|S1S2S4|++|Sn2Sn1Sn|+(1)n1(|S1S2S3Sn)|)
即:奇数个集合相交前面的系数为正,偶数个集合相交系数为负。

  • 数学证明
    若证:|S1S2S3Sn|=(|S1|+|S2|+|S3|++|Sn|)(|S1S2|+|S1S3|++|Sn1Sn|+(|S1S2S3|+|S1S2S4|++|Sn2Sn1Sn|+(1)n1(|S1S2S3Sn)|)
    只需证:对于任意一个其中的元素x,其属于n个集合中的k个,都有:Ck1Ck2++(1)k1Ckk=1即可,我们发现对于(11)k二项式展开有:(1+1)k=1Ck1+Ck2Ck3++(1)kCkk0=1Ck1+Ck2Ck3++(1)kCkkCk1Ck2++(1)k1Ckk=1,证毕。
  • 代码实现
    给定一个n和m个不同的质数P1,P2,P3Pm,求出1-n中至少能被一个P整除的数有多少个。
#include<iostream>
using namespace std;
typedef long long LL;
const int M=20;
int p[M];
int main()
{
    int n,m;
    cin>>n>>m;
    for(int i=0;i<m;i++)
    {
        int x;
        scanf("%d",&x);
        p[i]=x;
    }
    int res=0;
    for(int i=1;i<1<<m;i++)//将所有质数选择情况用1-(2^m-1)的二进制数这2^m-1种情况表示,其中1代表选了这个质数,0表示没选
    {
        int t=1,cnt=0;
        for(int j=0;j<m;j++)
        {
            if(i>>j&1)
            {
                if((LL)t*p[j]>n)
              {
                t=-1;
                break;
              }
              t*=p[j];
              cnt++;
            }
        }
        if(t!=-1)
        {
            if(cnt%2)
            {
                res+=n/t;
            }
            else
            {
                res-=n/t;
            }
        }
        
    }
    printf("%d\n",res);
    
    return 0;
}
  • 代码思路及细节
    由数学知识显然有:1-n中能被Pi整除的数有nPi个,且1-n中能被PiPk同时整除的数有nPiPk个,以此类推:1-n中能被P1P2Pm整除的数有nP1P2Pm个。
    对于质数选择的表示我们用了一个小技巧,就是用12m12m1个数的二进制来表示,1表示选了这个质数,0代表没有选,例如101就表示选了第一个和第三个质数来求它们在1~n至少能被其中一个数整除的数有多少个。
posted @   Taco_gu  阅读(81)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
点击右上角即可分享
微信分享提示