[Jzoj] 1241. Number

博客围绕求第k小幸运数展开。给定N个数,若其中仅有一个数能整除m,则m为幸运数。解题采用二分答案法,算出1到mid区间内符合条件的数,通过暴力枚举选数、计算lcm并结合容斥原理实现,同时要注意数据类型及范围。

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

题目大意

N(2&lt;=N&lt;=15)N(2&lt;=N&lt;=15)N(2<=N<=15)个数A1,A2,....,AnA_1,A_2,....,A_nA1,A2,....,An−_-1_11,AnA_nAn,如果在这NNN个数中,有且仅有一个数能整除mmm,那么整数mmm就是一个幸运数,你的任务就是在给定A1,A2,....,AnA_1,A_2,....,A_nA1,A2,....,An−_-1_11,AnA_nAn的情况下,求出第kkk小的幸运数。

题目解析

二分答案,算出111~midmidmid区间内有多少个数符合条件,这个可以暴力枚举选哪些数,算出lcmlcmlcm,再用容斥原理做。要注意的是开longlonglong longlonglong而且lcmlcmlcm可能会超出longlonglong longlonglong范围。

代码

#include<bits/stdc++.h>
#define LL long long
using namespace std;
LL n,k,b=1e16;
LL a[20];
bool flag[20];
LL gcd(LL x,LL y) {return y==0?x:gcd(y,x%y);}
LL lcm(LL x,LL y) {return x*y/gcd(x,y);}
struct A
{
	LL num,p;
}f[1000005];
int cnt;
void dfs(int lev)
{
	if(lev>n)
	{
	  bool ff=1;
	  LL p=1,num=0;
	  for(int i=1;i<=n;i++)
	   if(flag[i])
	   {
	   	 num++,p=lcm(p,a[i]);
	   	 if(p>1e15)
	   	 {
	   	   ff=0;
	   	   break;
		 }
	   }
	  if(ff) f[++cnt].num=num,f[cnt].p=p;
	  return;
	}
	dfs(lev+1);
	flag[lev]=1;
	dfs(lev+1);
	flag[lev]=0;
}
bool check(LL x)
{
	LL ans=0;
	for(int i=1;i<=cnt;i++)
	 if(f[i].num%2==1) ans+=floor(x/f[i].p)*f[i].num;
	 else if(f[i].num%2==0) ans-=floor(x/f[i].p)*f[i].num;
	if(ans>=k) return true;
	else return false;
}
int main()
{
	cin>>n>>k;
	for(int i=1;i<=n;i++) cin>>a[i];
	dfs(1);
	LL l=0,r=1e15,mid;
	while(l<=r)
	{
	  mid=(l+r)>>1;
	  if(check(mid)) r=mid-1,b=min(b,mid);
	  else l=mid+1;
	}
	while(check(b)) b--;
	cout<<b+1;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值