1. 程式人生 > >lightoj 1289【求1到n的lcm取模】

lightoj 1289【求1到n的lcm取模】

文章目錄

題目連結:

https://vjudge.net/contest/269935#problem
直接求lcm途中的答案會很大,而且不能直接取模
以前就只知道兩個數的lcm怎麼求,但是多個數怎麼辦呢?以為也是除以他們的gcd就行了,結果不對,自己推也沒有推出來,網上看了大佬們的想法才知道,是要找每個質因子最高次的

比如說2 4 6,這三個數的lcm=12,gcd=2
直接246/gcd是不等於12的

這三個數闊以寫成 2

1 , 2 2 , 2 1 3
1
2^1,2^2,2^13^1
2這個質因子的最高次是2
3這個質因子的最高次是1
因此最後的答案應該是 2 2 3 1
= 12 2^23^1=12
這樣來的

然後就是這道題了,因為一個數n的質因子肯定是小於 n \sqrt{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;
	}
}