无关(relationship)

无关(relationship)

题目

链接:https://ac.nowcoder.com/acm/problem/16513
来源:牛客网

时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 32768K,其他语言65536K
64bit IO Format: %lld
题目描述
若一个集合A内所有的元素都不是正整数N的因数,则称N与集合A无关。

给出一个含有k个元素的集合A={a1,a2,a3,…,ak},求区间[L,R]内与A无关的正整数的个数。
保证A内的元素都是素数。
输入描述:
输入数据共两行:

第一行三个正整数L,R,k,意义如“题目描述”。

第二行k个正整数,描述集合A,保证k个正整数两两不相同。
输出描述:
输出数据共一行:

第一行一个正整数表示区间[L,R]内与集合A无关的正整数的个数
示例1
输入
复制
1 10 4
2 3 5 7
输出
复制
1
示例2
输入
复制
2 10 4
2 3 5 7
输出
复制
0
说明
对于30%的数据:1<=L<=R<=10^6

对于100%的数据:1<=L<=R<=10^18,1<=k<=20,2<=ai<=100

题解

L和R数据规模1e18,很明显是不可能从L到R遍历暴力求解,注意到K<=20,很明显就从20个数下手,因此我们的思路就是,排除所有的倍数,剩下的就是无关数了。

于是就考虑用容斥原理:
∣ A 1 ∪ A 2 ∪ . . . ∪ A n ∣ = ∑ 1 ≤ i ≤ n ∣ A i ∣ − ∑ 1 ≤ i , j ≤ n ∣ A i ∩ A j ∣ + ∑ 1 ≤ i , j , k ≤ n ∣ A i ∩ A j ∩ A k ∣ − . . . . . . \mid A_1 \cup A_2 \cup ... \cup A_n \mid=\sum_{1\le i\le n}{ \mid A_i \mid}-\sum_{1\le i,j\le n} {\mid A_i \cap A_j \mid}+\sum_{1\le i,j,k\le n}{ \mid A_i \cap A_j \cap A_k \mid}-...... A1A2...An=1inAi1i,jnAiAj+1i,j,knAiAjAk......

需要注意的是20个素数的积可能爆long long,因此需要判断与剪枝。

由于本人数学水平捉急,只会求0到n之间的倍数个数,所以L到R之间的倍数个数采用0~R - 0~L,枚举过程这里采用状压,感觉2^k的遍历状压很舒服

代码

#include<cstdio>  
#include<iostream>  
#include<cstring>  
#include<cmath>  
#include <cctype>  
#include<string>  
#include<vector>  
#include<stack>  
#include<queue>  
#include<set>  
#include <algorithm>  
#define ll long long  
#include<iomanip>  
#define mms(a) memset(a,0,sizeof(a))  
  
using namespace std;  
  
ll l,r,k;  
int a[21];  
  
ll Find(ll N)  
{  
    ll sum=0;  
    for(int i=1;i<(1<<k);i++)  
    {  
        ll cnt=0,cmp=1;  
        for(int j=0;j<k;j++)  
        {  
            if(i&(1<<j))  
            {  
                cnt++;  
                cmp*=a[j];  
            }  
            if(cmp>N)  
            {  
                cmp=0;  
                break;  
            }  
        }  
        if(cmp && cnt%2)  
            sum+=N/cmp;  
        else if(cmp)  
            sum-=N/cmp;  
    }  
    return N-sum;  
}  
  
int main( )  
{  
    cin >> l >> r >> k;  
    for(int i=0;i<k;i++)  
        cin >> a[i];  
    cout << Find(r)-Find(l-1) << endl;  
    return 0;  
}  
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值