lightoj 1289【多个数求最小公倍数】

博客讲述了如何解决lightoj 1289问题,即求多个数的最小公倍数(LCM)。内容指出直接求LCM可能会导致答案过大,而应该寻找每个质因子的最高次幂。通过举例解释了如何计算多个数的LCM,提到对于质因子的枚举可以限制在1e4内。博主比较了手动实现的位图方法和STL中的bitset方法,发现在本地测试中位图更快,但在OJ上bitset方法更快,提出了可能的优化或机器差异的问题。

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

题目链接:

https://vjudge.net/contest/269935#problem
直接求lcm途中的答案会很大,而且不能直接取模
以前就只知道两个数的lcm怎么求,但是多个数怎么办呢?以为也是除以他们的gcd就行了,结果不对,自己推也没有推出来,网上看了大佬们的想法才知道,是要找每个质因子最高次的

比如说2 4 6,这三个数的lcm=12,gcd=2
直接 2 ⋅ 4 ⋅ 6 g c d \frac{2\cdot 4\cdot 6}{gcd} gcd246是不等于12的

这三个数阔以写成 2 1 , 2 2 , 2 1 3 1 2^1,2^2,2^13^1 21,22,2131
2这个质因子的最高次是2
3这个质因子的最高次是1
因此最后的答案应该是 2 2 3 1 = 12 2^23^1=12 2231=12这样来的

然后就是这道题了,因为一个数n的质因子肯定是小于 n \sqrt{n} n 的,所以枚举只用枚举到1e4,

然后就是筛质数那里,用到了啥位图,看懂了之后其实就是把每一位都用起来了,而stl里面有个bitset就是操作位的,好像原理就是位图这么个原理

我用clock()测一下时间,发现筛质数那里手写的位图要2000+ms,而bitset的要4000+ms
但oj上手写的AC时间是1736ms,bitset是1611ms ???
这是什么鬼啊?是oj有优化啥的嘛?还是我电脑太歪啦

手写位图:

#include"bits/stdc++.h"
using namespace std;
typedef long long LL;
typedef unsigned int uint;
const int maxn=1e8+5;
//clock_t t1,t2;
uint vis[maxn/32+50];
uint prime[6000000],sum[6000000];//质数,质数乘积前缀 
void Set(int i)
{
	int x=i/32,y=i%32;
	vis[x]|=((uint)1)<<y;
}
int Get(int i)
{
	int x=i/32,y=i%32;
	return vis[x]&((uint)1<<y);
}
int cnt=0;
void PHI(int n)
{

//	t1=clock();
	for(int i=2; i<=n; i++)
	{
		if(Get(i)==0)prime[cnt++]=i;
		for(int j=0; j<cnt&&(LL)i*prime[j]<=n; j++)
		{
			Set(i*prime[j]);
			if(i%prime[j]==0)break;
		}
	}
//	t2=clock();
	sum[0]=prime[0];
	for(int i=1; i<cnt; i++)sum[i]=sum[i-1]*prime[i];
}
uint solve(LL n)
{
	int pos=upper_bound(prime,prime+cnt,n)-prime-1;//找比n小的质数
	uint ans=sum[pos];
	for(int i=0; i<cnt&&(LL)prime[i]*prime[i]<=n; i++)
	{
		LL tp=prime[i];
		while(tp*prime[i]<=n)tp*=prime[i];
		ans*=tp/prime[i];
	}
	return ans;
}
int main()
{
	PHI(maxn-5);
//	cout<<"t2-t1="<<t2-t1<<endl;
	int T;
	cin>>T;
	for(int Case=1; Case<=T; Case++)
	{
		LL N;
		cin>>N;
		cout<<"Case "<<Case<<": "<<solve(N)<<endl;
	}
}

用bitset


#include"bits/stdc++.h"
using namespace std;
typedef long long LL;
typedef unsigned int uint;
const int maxn=1e8+5;
//clock_t t1,t2;
bitset<maxn> bt;
uint prime[6000000],sum[6000000];//质数,质数乘积前缀 
int cnt=0;
void PHI(int n)
{
//	t1=clock();
	bt.flip();
	for(int i=2; i<=n; i++)
	{
		if(bt[i])prime[cnt++]=i;
		for(int j=0; j<cnt&&(LL)i*prime[j]<=n; j++)
		{
			bt[i*prime[j]]=0;
			if(i%prime[j]==0)break;
		}
	}
//	t2=clock();
	sum[0]=prime[0];
	for(int i=1; i<cnt; i++)sum[i]=sum[i-1]*prime[i];
}
uint solve(LL n)
{
	int pos=upper_bound(prime,prime+cnt,n)-prime-1;//找比n小的质数
	uint ans=sum[pos];
	for(int i=0; i<cnt&&(LL)prime[i]*prime[i]<=n; i++)
	{
		LL tp=prime[i];
		while(tp*prime[i]<=n)tp*=prime[i];
		ans*=tp/prime[i];
	}
	return ans;
}
int main()
{
	PHI(maxn-5);
//	cout<<"t2-t1="<<t2-t1<<endl;
	int T;
	cin>>T;
	for(int Case=1; Case<=T; Case++)
	{
		LL N;
		cin>>N;
		cout<<"Case "<<Case<<": "<<solve(N)<<endl;
	}
}

1。打开功能是专门用于对C语言文件自动提取显示所需要的汉字,进行点阵码数据转换的, 在您的C语言程序中,有一点需要特别留意:您的注解中请不要使用双引号,否则会引起 提取错误。 软件包中的文件ee.c作为一个简单例程供提取测试用。 2。提取以后的点阵码可以随意修改点阵数据,使用鼠标的左键为加一点,右键为擦除一点。 修改完毕请按旁边的确认键将数据记录到点阵码中,否则您的修改将自动放弃。 3。点阵码可以随意平移,请谨慎使用。平移之前请查看一遍所有的字符点阵图,平移有可能 会丢失边界点,移出了边界的点阵将被丢弃,不可恢复。 平移前请确认是否有必要进行全体字符一起移动。 4。用户自定义特殊字符的建立,首先选定点阵数据,在下面的汉字输入窗口输入几个您不使 用的汉字,确认。然后生成了这些汉字的点阵码,再将他们清空(使用平移按钮中间的那 块抹布),就可以用鼠标描绘你的图案了,最后别忘了打“确认”键。 5。ASCII字符可以自动提取0x20~0x7f的全部,最后一个0x7f一般都没有用,可以手工将它删 除,也可以利用它做一个简单的特殊字符。 汉字库中也包含有ascii字符,但是经查对与这三个ascii库基本一样,所以就不再重复。 6。保存文件:C语言格式的默认为.h类型,汇编格式的默认为.inc类型,只要将他们加入到 您的工程中就可以了。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值