[Luogu] P4626 一道水题 II

时间:2021-08-20 22:29:42
[Luogu] P4626 一道水题 II

---恢复内容开始---

题目描述

一天,szb 在上学的路上遇到了灰太狼。

灰太狼:帮我们做出这道题就放了你。
szb:什么题?
灰太狼:求一个能被 [1,n] 内所有数整除的最小数字,并对 100000007 取模。
szb:这题太水了,就让我小弟来做好了。

然后你就光荣的接受了这个任务。

输入输出格式

输入格式:

一行一个数 n。

输出格式:

一行一个数 ans。

数据范围

n <= 1e8

题目解析

真是凶残,1e8的数据

题目分析难度不大,很容易想到是求1~n的最小公倍数,但要求效率较高。

以1~7举例:

for(int i = ;i <= ;i++) {
分解质因数(i);
ans *= (i的各个质因数 - ans中已有的各个质因数)
}

我用pri[i]表示i的质因数集合,ans[]表示ans是由哪些数相乘得到的。

i = 1时,不管

i = 2时,pri[2] = 2,ans[] = 1,所以ans *= 2

i = 3时,pri[3] = 3,ans[] = 1,2,所以ans *= 3

i = 4时,pri[4] = 2,2,ans[] = 1,2,3,此时ans里有一个i了,要成为4的最小公倍数只需要*2就可以了,ans[] = 1,2,2,3

……

枚举质数,int now = 1;while(质数*now <= n) 质数*now。

Code

#include<iostream>
#include<cstdio>
#include<bitset>
#include<cmath>
using namespace std; const int MAXN = 1e8 + ;
const int MAXM = ;
const int p = ; int n,cnt;
long long ans;
int prime[MAXM];
bool notprime[MAXN]; inline void Prime_Sieve(int n) {
notprime[] = true;
for(register int i = ;i <= n;i++) {
if(notprime[i] == ) prime[++cnt] = i;
for(register int j = ;j <= cnt;j++) {
if(prime[j] * i > n) break;
notprime[prime[j]*i] = true;
if(!(i%prime[j])) break;
}
}
} int main() {
scanf("%d",&n);
Prime_Sieve(n);
long long tmp;
ans = ;
for(register int i = ;i <= cnt;i++) {
tmp = prime[i];
while(tmp*tmp <= n) tmp *= tmp;
while(tmp*prime[i] <= n) tmp *= prime[i];
ans *= tmp % p;
ans %= p;
}
printf("%lld\n",ans%p);
return ;
}