文章标题 HackerRank - mehta-and-the-typical-supermarket (容斥原理)

本文解析了HackerRank上的一道购物问题,通过预处理最小公倍数并利用容斥原理来高效解决询问,计算特定价格范围内可用不同类型的硬币购买的商品数量。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

HackerRank - mehta-and-the-typical-supermarket

Mehta is a very rich guy. He has types of coins, and each type of coin is available in an unlimited supply.

So Mehta goes to a supermarket to buy monthly groceries. There he sees that every item has a unique price, that is, no two items have the same price.

Now, the supermarket owner tells Mehta that they are selling items in the price range only on that particular day. He also tells Mehta that for every price, there is an item in the shop.

The supermarket has recently adopted a weird new tradition: Mehta may only use a single type of coin for each item he purchases. For example, he could pay for an item of price 4 with two 2-coins, but not with a 3-coin and a 1-coin.

As you know Mehta is very weak at calculations, so he wants you to do these calculations for him and tell how many different types of items he can buy.

Input Format
The first line of input contains , the number of types of coins Mehta has.
Then the next lines contain an integer each: the ith line contains , the value of Mehta’s ith type of coin.

Then the next line contains a number , the number of days Mehta goes shopping.
Then each of the next lines contains numbers and , denoting that they are selling items in price range on that particular day.

Output format
There will be lines, each containing the number of distinct items that can be bought at that particular day.

Constraints

Sample Input

4
2
3
4
5
3
1 10
2 20
3 7
Sample output

8
14
4
Explanation
For and you can buy items of price .
For and you can buy items of price .
For and you can buy items of price .
题意:给出n个数A[i],然后有D个询问,包括L,R,然后求出【L,R】其中能被A[i]整除的数的数目。
分析:用F(a1,a2,…,an)表示在【L,R】期间能被a1,a2,…,an整除的数目,即答案。
然后根据容斥原来得
F(a1,a2,…,an)=∑F(ai)-∑F(ai,aj)+∑F(ai,aj,ak)-∑F(ai,aj,ak,al)…
而F(a1,a2,…,an)=F(lcm(a1,a2,…an);
且F(a)=R/a-(L-1)/a;

此题中的lcm有可能会出现爆long long ,所以得特断一下
然后得预处理一下, 不然会超时

#include<iostream>
#include<string>
#include<cstdio>
#include<cstring>
#include<vector>
#include<math.h>
#include<map>
#include<queue> 
#include<algorithm>
using namespace std;
const int inf = 0x3f3f3f3f;
typedef pair<int,int> pii;
typedef pair<long long ,long long> pll;
const long long INF = 2000000000000000000;

pll p[1<<18];
int n,d;
long long a[50];
long long L,R;

long long real(long long a,long long b){//a*b有可能爆longlong 
    return (INF/a>=b?a*b:INF);
}

long long gcd (long long a,long long b){//最大公约数 
    if (b==0)return a;
    return gcd(b,a%b);
} 

void init(int n){//预处理,先求出对应的最小公倍数以及cnt 
    long long lcm;
    int cnt=0;
    for (int i=1;i<(1<<n);i++){
        lcm=1;
        cnt=0;
        for (int j=0;j<n;j++){
            if (i&(1<<j)){
                cnt++;
                lcm=real(lcm/gcd(lcm,a[j]),a[j]);
            }
        }
        p[i].first=lcm;
        p[i].second=cnt;
    }
}


int main ()
{
    scanf ("%d",&n);
    for (int i=0;i<n;i++){
        scanf("%lld",&a[i]); 
    }
    init(n);//预处理 
    scanf ("%d",&d);
    while (d--){
        scanf ("%lld%lld",&L,&R);
        long long ans=0;
        for (int i=1;i<(1<<n);i++){
            long long tmp= (R/p[i].first-(L-1)/(p[i].first));
            if (p[i].second%2){
                ans+=tmp;
            }else ans-=tmp;
        }
        printf ("%lld\n",ans);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值