Acwing890能被整除的数题解【容斥原理模板题】

Acwing890能被整除的数题解

题目描述

题目链接:能被整除的数
在这里插入图片描述

问题分析

读题发现问题模型是求n中是p1,p2,…pm中至少一个整除的整数个数。
我们知道,n/p1便是1~n中能被p1整除的个数。依次,n/pi 便是1-n中能被pi整除的个数。  
  例如:1-10 中能被2整除的数是2,4,6,8,10这5个,也就是10/2 = 5,1-10中能被3整除的数是3,6,9这3个数,也就是10/3的整数部分。那么1~10中能被2、3中至少一个整除的数的个数并不是3+5= 8 ,其中6这个数既能被2整除,也能被3整除。那么这个就需要减去。
  这就是一个典型的容斥原理。
  我们从特殊到一般的推导过程如下图所示:
在这里插入图片描述
  因此我们需要计算出各种情况下的个数,然后有规律的累加起来,便是此问题的解。
那么这些情况如何找?我们发现每一项就是曾经在深度优先搜索里学过的m个数中选x个数的问题,我们将这x个数组合枚举出来的时候,将其累乘出一个数nowvalue,然后计算n/nowvalue便可得这个数列所对应的数能整除的个数。
  那么我们只需要通过深搜将这些组合数的情况一一搜出来并计算就可以了。
  再来说说这个程序的时间复杂度。根据上图中最后一行,我们发现求解式子的项数是2^m - 1,然后每一项的深度最坏情况下是m,因此本题的算法时间复杂度是O(2 ^ (m+1)),而m<=16.不会超时。

代码实现

#include<bits/stdc++.h>
using namespace std;
bool vis[18];
int n,m;
int a[18];
int temp;
void dfs(int k,int x,int pos,int nowvalue){
    if(nowvalue > n)  temp += 0;
    else if(x > k)  temp += n/nowvalue;
    else {
        for(int i = pos; i<= m; i++){
            if(!vis[i] && 1LL* nowvalue * a[i] <= n){
                vis[i] = true;
                dfs(k, x+1,i+1, nowvalue * a[i]);
                vis[i] = false;
            }
        }
    }
}
int main(){
    scanf("%d%d",&n,&m);
    for(int i = 1;i<= m; i++){
        scanf("%d",&a[i]);
    }
    int ans = 0,k = 1;
    for(int i = 1;i<= m; i ++,k = k * -1){
        temp = 0;
        dfs(i,1,1,1);
        ans = ans + k * temp;
    }
    printf("%d",ans);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值