UVAlive 4683 Find The Number

题目链接:http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=14336


题意:给一个含k个数的集合,符合条件的数当且仅当满足被集合中的一个数整除,求最小区间上界x,使得[1,x]内含有n个符合条件的数。


思路:二分答案+dfs容斥,如果用二进制枚举会超时。如果当前的倍数k是由x个数得到的,那么会有(n/k)个数之前会被那x个数单独都统计进去一次,所以是(n/k)*x。


#include <cstdio>
#include <cmath>
#include <cstring>
#include <string>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#include <stack>
#include <map>
#include <set>
#include <vector>
#include <sstream>
#include <queue>
#include <utility>
using namespace std;

#define rep(i,j,k) for (int i=j;i<=k;i++)
#define Rrep(i,j,k) for (int i=j;i>=k;i--)

#define Clean(x,y) memset(x,y,sizeof(x))
#define LL long long
#define ULL unsigned long long
#define inf 0x7fffffff
#define mod %100000007

int T;
int p[15];
int m;
LL k;
LL ans;

LL gcd(LL a , LL b)
{
    return (a%b==0)?b:gcd(b,a%b);
}


void dfs(int now , int num , LL lcm , LL n)
{
    if ( lcm > 1e15 ) return;
    if ( num & 1 )
        ans+=n/lcm*num;
    else ans-=n/lcm*num;
    rep(i,now+1,m)
        dfs( i , num+1 , lcm/gcd(lcm,p[i])*p[i] , n );
}

int main()
{
    cin>>T;
    while(T--)
    {
        scanf("%d %lld",&m,&k);
        rep(i,1,m) scanf("%d",p+i);
        LL L = 1;
        LL R = 1e15;
        LL mid;
        while(L<R)
        {
            ans = 0;
            mid = (L+R)>>1;
            rep(i,1,m)
                dfs(i,1,p[i],mid);

            if ( ans >= k )
                R = mid;
            else
                L = mid + 1;
        }
        cout<<L<<endl;
    }
    return 0;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值