数学 - 容斥原理 - 能被整除的数

数学 - 容斥原理 - 能被整除的数

1、容斥原理

设 有 n 个 集 合 S 1 , S 2 , . . . , S n , n 个 集 合 的 并 集 的 元 素 个 数 : 设有n个集合S_1,S_2,...,S_n,n个集合的并集的元素个数: nS1,S2,...,Snn ∣ S 1 ∪ S 2 ∪ . . . ∪ S n ∣ = ( ∑ i = 1 n ∣ S i ∣ ) − ( ∑ i , j = 1 n ∣ S i ∩ S j ∣ ) + ( ∑ i , j , k = 1 n ∣ S i ∩ S j ∩ S k ∣ ) − . . . |S_1∪S_2∪...∪S_n|=(\sum_{i=1}^n|S_i|)-(\sum_{i,j=1}^n|S_i∩S_j|)+(\sum_{i,j,k=1}^n|S_i∩S_j∩S_k|)-... S1S2...Sn=(i=1nSi)(i,j=1nSiSj)+(i,j,k=1nSiSjSk)...

抽 象 地 , 公 式 为 : 抽象地,公式为:

∑ k = 1 n   ∑ i 1 , i 2 , . . . , i k = 1 n ( − 1 ) k − 1 ∣ S i 1 ∩ S i 2 ∩ . . . ∩ S i k ∣ , \sum_{k=1}^n\ \sum_{i_1,i_2,...,i_k=1}^{n}(-1)^{k-1}|S_{i_1}∩S_{i_2}∩...∩S_{i_k}|, k=1n i1,i2,...,ik=1n(1)k1Si1Si2...Sik
其 中 i 1 ≠ i 2 ≠ . . . ≠ i k , k ∈ [ 1 , n ] 是 相 交 集 合 的 个 数 。 其中i_1≠i_2≠...≠i_k,k∈[1,n]是相交集合的个数。 i1=i2=...=ikk[1,n]

说明:

对 于 : 对于:
∣ S 1 ∪ S 2 ∪ . . . ∪ S n ∣ = ( ∑ i = 1 n ∣ S i ∣ ) − ( ∑ i , j = 1 n ∣ S i ∩ S j ∣ ) + ( ∑ i , j , k = 1 n ∣ S i ∩ S j ∩ S k ∣ ) − . . . |S_1∪S_2∪...∪S_n|=(\sum_{i=1}^n|S_i|)-(\sum_{i,j=1}^n|S_i∩S_j|)+(\sum_{i,j,k=1}^n|S_i∩S_j∩S_k|)-... S1S2...Sn=(i=1nSi)(i,j=1nSiSj)+(i,j,k=1nSiSjSk)...

假 设 元 素 x ∈ S = S 1 ∪ S 2 ∪ . . . ∪ S n , 且 x 属 于 S 的 k 个 子 集 , 假设元素x∈S=S_1∪S_2∪...∪S_n,且x属于S的k个子集, xS=S1S2...SnxSk

那 么 在 统 计 ∑ i = 1 n ∣ S i ∣ 时 就 会 统 计 C k 1 = k 次 , 由 于 x 可 能 同 时 属 于 两 个 集 合 , 这 部 分 就 被 多 加 了 , 要 减 去 那么在统计\sum_{i=1}^n|S_i|时就会统计C_k^1=k次,由于x可能同时属于两个集合,这部分就被多加了,要减去 i=1nSiCk1=kx

在 统 计 ∑ i , j = 1 n ∣ S i ∩ S j ∣ 时 就 会 统 计 C k 2 次 , 减 去 这 部 分 后 , 由 于 x 又 可 能 同 时 属 于 3 个 集 合 , 这 部 分 被 多 减 了 , 在统计\sum_{i,j=1}^n|S_i∩S_j|时就会统计C_k^2次,减去这部分后,由于x又可能同时属于3个集合,这部分被多减了, i,j=1nSiSjCk2x3

. . . ... ...

则 对 于 元 素 x , 整 个 等 式 右 侧 会 被 统 计 C k 1 − C k 2 + . . . + ( − 1 ) k − 1 C k k = ∑ i = 1 k ( − 1 ) i − 1 C k i 次 。 则对于元素x,整个等式右侧会被统计C_k^1-C_k^2+...+(-1)^{k-1}C_k^k=\sum_{i=1}^{k}(-1)^{i-1}C_k^i次。 xCk1Ck2+...+(1)k1Ckk=i=1k(1)i1Cki

2、能被整除的数

给定一个整数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

分析:

对 于 每 个 质 数 p i , n 以 内 能 够 被 p i 整 除 的 数 的 个 数 为 ⌊ n p i ⌋ 个 , 记 集 合 S i 表 示 n 以 内 能 够 被 p i 整 除 的 数 , 则 ∣ S i ∣ = ⌊ n p i ⌋ 。 对于每个质数p_i,n以内能够被p_i整除的数的个数为\lfloor\frac{n}{p_i}\rfloor个,记集合S_i表示n以内能够被p_i整除的数,则|S_i|=\lfloor\frac{n}{p_i}\rfloor。 pinpipinSinpiSi=pin

由 于 给 定 的 p 都 是 质 数 , 故 能 够 同 时 被 p i 和 p j 都 整 除 的 数 共 有 ⌊ n p i ⋅ p j ⌋ 个 , 以 此 类 推 . . . 由于给定的p都是质数,故能够同时被p_i和p_j都整除的数共有\lfloor\frac{n}{p_i·p_j}\rfloor个,以此类推... ppipjpipjn...

那 么 ∣ S 1 ∪ S 2 ∪ . . . ∪ S m ∣ = ( ∑ i = 1 m ∣ S i ∣ ) − ( ∑ i , j = 1 m ∣ S i ∩ S j ∣ ) + ( ∑ i , j , k = 1 m ∣ S i ∩ S j ∩ S k ∣ ) − . . .    = ( ∑ i = 1 m ⌊ n p i ⌋ ) − ( ∑ i , j = 1 m ⌊ n p i ⋅ p j ⌋ ) + . . . 那么|S_1∪S_2∪...∪S_m|=(\sum_{i=1}^m|S_i|)-(\sum_{i,j=1}^m|S_i∩S_j|)+(\sum_{i,j,k=1}^m|S_i∩S_j∩S_k|)-...\\\qquad\qquad\qquad\qquad\qquad\ \ =(\sum_{i=1}^m\lfloor\frac{n}{p_i}\rfloor)-(\sum_{i,j=1}^m\lfloor\frac{n}{p_i·p_j}\rfloor)+... S1S2...Sm=(i=1mSi)(i,j=1mSiSj)+(i,j,k=1mSiSjSk)...  =(i=1mpin)(i,j=1mpipjn)+...

具体落实:

对 于 m 个 质 数 , 共 有 2 m − 1 个 非 空 集 合 , 分 别 对 应 着 一 些 集 合 的 交 集 。 对于m个质数,共有2^m-1个非空集合,分别对应着一些集合的交集。 m2m1

用 一 个 m 位 二 进 制 数 来 表 示 这 样 的 集 合 , 若 改 二 进 制 数 的 第 i 位 是 1 , 表 示 这 个 集 合 中 的 数 能 够 整 除 p i 。 用一个m位二进制数来表示这样的集合,若改二进制数的第i位是1,表示这个集合中的数能够整除p_i。 mi1pi

① 、 从 [ 1 , 2 m − 1 ] 枚 举 所 有 可 能 的 状 态 。 ①、从[1,2^m-1]枚举所有可能的状态。 [1,2m1]

② 、 对 于 每 个 状 态 , 需 要 统 计 这 个 状 态 所 包 含 的 质 数 的 乘 积 t = ∏ i = 1 m p i , 状 态 中 1 的 个 数 c n t 。 ②、对于每个状态,需要统计这个状态所包含的质数的乘积t=\prod_{i=1}^mp_i,状态中1的个数cnt。 t=i=1mpi1cnt

③ 、 若 t > n , 说 明 n 以 内 能 够 被 当 前 集 合 内 的 所 有 质 数 都 整 除 的 数 的 个 数 ⌊ n t ⌋ = 0 , 此 时 可 以 直 接 退 出 循 环 。 ③、若t>n,说明n以内能够被当前集合内的所有质数都整除的数的个数\lfloor\frac{n}{t}\rfloor=0,此时可以直接退出循环。 t>nntn=0退

④ 、 若 c n t 为 奇 数 , 根 据 公 式 , 答 案 需 要 加 上 ⌊ n t ⌋ , 否 则 答 案 应 当 减 去 ⌊ n t ⌋ 。 ④、若cnt为奇数,根据公式,答案需要加上\lfloor\frac{n}{t}\rfloor,否则答案应当减去\lfloor\frac{n}{t}\rfloor。 cnttntn

代码:

#include<iostream>

#define ll long long

using namespace std;

int n,m,p[20];

int main()
{
    cin>>n>>m;
    for(int i=0;i<m;i++) cin>>p[i];
    
    int res=0;
    for(int i=1;i<1<<m;i++)
    {
        ll t=1;
        int cnt=0;
        for(int j=0;j<m;j++)
            if(i>>j&1)
            {
                cnt++;
                t*=p[j];
                if(t>n) break;
            }
        if(cnt&1) res+=n/t;
        else res-=n/t;
    }
    
    cout<<res<<endl;
    
   	return 0;
}
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值