2023NOIP A层联测10 集合

文章讨论了一个关于整数n和大小为m的可重集B的计算问题,通过一系列操作将n变为其他数,分析了取值个数并提出了一种时间复杂度为O(n√nlogn)的解决方案。

题目大意

你有一个正整数nnn和一个大小为mmm的可重集BBB

每次你可以可重集BBB中选择一个数xxx,将xxx变为⌊nx⌋\lfloor \dfrac nx\rfloorxn

问通过上述操作,能将nnn变成多少种不同的数。

1≤n≤1015,1≤x≤1015,1≤m≤101\leq n\leq 10^{15},1\leq x\leq 10^{15},1\leq m\leq 101n1015,1x1015,1m10

时间限制1s1s1s


题解

首先,我们知道,⌊nd⌋\lfloor \dfrac nd\rfloordn的取值个数是O(n)O(\sqrt n)O(n)的。证明如下:

  • 1≤d≤n1\leq d\leq \sqrt n1dn时,最多有n\sqrt nnddd,也就是n\sqrt nn⌊nx⌋\lfloor \dfrac nx\rfloorxn,故此时取值个数是O(n)O(\sqrt n)O(n)
  • n<d≤n\sqrt n<d\leq nn<dn时,1≤⌊nx⌋≤n1\leq \lfloor \dfrac nx\rfloor\leq \sqrt n1xnn,故此时取值个数是O(n)O(\sqrt n)O(n)

所以,⌊nd⌋\lfloor \dfrac nd\rfloordn的取值个数是O(n)O(\sqrt n)O(n)的。

直接搜索,然后用mapmapmap记录每个值是否被搜索过。不过,因为调用mapmapmap还要一个log⁡\loglog的时间复杂度,所以我们考虑小于等于n\sqrt nn的数用一个数组标记,大于n\sqrt nn的数用mapmapmap标记。

时间复杂度为O(nlog⁡n)O(\sqrt n\log n)O(nlogn)

最坏情况下的数据如下:

1000000000000000 10
2 3 5 7 11 13 17 19 23 29

如果用上述方法来实现,这个数据只要跑不到500ms500ms500ms,所以是可以过的。

code

#include<bits/stdc++.h>
using namespace std;
int m;
long long n,ans=0,x[15];
bool z[33000005];
map<long long,bool>mp;
void dfs(long long t){
	if(t<=sqrt(n)){
		if(z[t]) return;
		z[t]=1;
	}
	else{
		if(mp[t]) return;
		mp[t]=1;
	}
	++ans;
	for(int i=1;i<=m;i++){
		dfs(t/x[i]);
	}
}
int main()
{
//	freopen("set.in","r",stdin);
//	freopen("set.out","w",stdout);
	scanf("%lld%d",&n,&m);
	for(int i=1;i<=m;i++){
		scanf("%lld",&x[i]);
		if(x[i]==1){
			--i;--m;
		}
	}
	sort(x+1,x+m+1);
	m=unique(x+1,x+m+1)-x-1;
	dfs(n);
	printf("%lld",ans);
	return 0;
}
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值