写在前面
笔者是一名十八线蒟蒻ACMer,文中可能会有多处错误与疏漏,欢迎指出。
原题题面
原题地址
时间:3 seconds
空间:256M
For the multiset of positive integers
s
=
s
1
,
s
2
,
…
,
s
k
s={s_1,s_2,…,s_k}
s=s1,s2,…,sk, define the Greatest Common Divisor (GCD) and Least Common Multiple (LCM) of s as follow:
g
c
d
(
s
)
gcd(s)
gcd(s) is the maximum positive integer
x
x
x, such that all integers in
s
s
s are divisible on
x
x
x.
l
c
m
(
s
)
lcm(s)
lcm(s) is the minimum positive integer
x
x
x, that divisible on all integers from
s
s
s.
For example,
g
c
d
(
8
,
12
)
=
4
,
g
c
d
(
12
,
18
,
6
)
=
6
gcd({8,12})=4,gcd({12,18,6})=6
gcd(8,12)=4,gcd(12,18,6)=6 and
l
c
m
(
4
,
6
)
=
12
lcm({4,6})=12
lcm(4,6)=12. Note that for any positive integer
x
x
x,
g
c
d
(
{
x
}
)
=
l
c
m
(
{
x
}
)
=
x
gcd(\{x\})=lcm(\{x\})=x
gcd({x})=lcm({x})=x.
Orac has a sequence
a
a
a with length
n
n
n. He come up with the multiset
t
=
{
l
c
m
(
a
i
,
a
j
)
∣
i
<
j
}
t=\{lcm({a_i,a_j}) | i<j\}
t={lcm(ai,aj)∣i<j}, and asked you to find the value of
g
c
d
(
t
)
gcd(t)
gcd(t) for him. In other words, you need to calculate the GCD of LCMs of all pairs of elements in the given sequence.
Input
The first line contains one integer
n
n
n
(
2
≤
n
≤
1
e
5
)
(2≤n≤1e5)
(2≤n≤1e5).
The second line contains
n
n
n integers,
a
1
,
a
2
,
…
,
a
n
a_1,a_2,…,a_n
a1,a2,…,an
(
1
≤
a
i
≤
2
e
5
)
(1≤a_i≤2e5)
(1≤ai≤2e5).
Output
Print one integer:
g
c
d
(
{
l
c
m
(
a
i
,
a
j
)
∣
i
<
j
}
)
gcd(\{lcm({a_i,a_j}) | i<j\})
gcd({lcm(ai,aj)∣i<j}).
InputExample
10
540 648 810 648 720 540 594 864 972 648
OutPutExample
54
题面分析
给你
n
n
n个数,让你求出两两组合的LCM的GCD。
先放个作者的题解。
注意到
n
n
n的数字很大,所以暴力一定T飞,因此考虑别的方法。
我想到了质因子分解。
由唯一分解定理可知,一个数可以被分解为
p
1
k
1
p
2
k
2
p
3
k
3
.
.
.
p
m
k
m
p_1^{k_1}p_2^{k_2}p_3^{k_3}...p_m^{k_m}
p1k1p2k2p3k3...pmkm的形式。
LCM可以认为是在每个
k
i
k_i
ki之中取较大值,
GCD可以认为是在每个
k
i
k_i
ki之中取较小值。
于是我们可以直接考虑将
n
n
n个数质因子分解,对每个质因子进行处理。
于是,问题就变成如下。
已知数列
k
i
k_i
ki,求出
M
i
n
(
M
a
x
(
k
i
,
k
j
)
)
(
i
≤
j
)
Min(Max(k_i,k_j))(i\leq j)
Min(Max(ki,kj))(i≤j)。
我们不妨设
k
i
≤
k
j
k_i\leq k_j
ki≤kj,可以发现,
M
i
n
(
M
a
x
(
k
i
,
k
j
)
)
(
i
≤
j
)
Min(Max(k_i,k_j))(i\leq j)
Min(Max(ki,kj))(i≤j)就是
k
2
k_2
k2。
因为两两取最大值中的最小值,一定是
M
a
x
(
k
1
,
k
2
)
=
k
2
Max(k_1,k_2)=k_2
Max(k1,k2)=k2是最小的。
于是我们的步骤如下:
1.对n个数质因子分解。
2.求出每个质因子系数里第二小的。
3.合并求出答案。
这里可以注意几个细节。
如果满足某个
k
i
=
0
k_i=0
ki=0的数字出现了两次及以上,那
k
2
=
0
k_2=0
k2=0,不予考虑。
如果满足某个
k
i
=
0
k_i=0
ki=0的数字出现了一次,那
k
2
k_2
k2为最小的不为零的系数。
如果满足某个
k
i
=
0
k_i=0
ki=0的数字没有出现,那
k
2
k_2
k2就是第二小的不为零的系数。
AC代码(311ms)
#include<bits/stdc++.h>
using namespace std;
long long a[2000005];//a是原数组
long longfactor[2000005];//factor[i]是质因子i出现的次数
vector<int> k[2000005];///k[i][j]数组表示质因子为i的第j个的个数
long quick_pow(long long a,long long b)//二进制快速乘,合并质因子与其系数时可用
{
long long ans=1;
long long base=a;
while(b!=0)
{
if(b&1)
ans=ans*base;
base=base*base;
b>>=1;
}
return ans;
}
int main()
{
long long n;
scanf("%lld",&n);
for(int i=1;i<=n;i++)
{
scanf("%lld",&a[i]);
long long x=a[i];
for(int j=2;j*j<=x;j++)
{
if(x%j==0)
{
factor[j]++;
int count=0;
while(x%j==0)
{
x/=j;
count++;
}
k[j].push_back(count);
}
}
if(x!=1)
{
factor[x]++;
k[x].push_back(1);//可以证明,对于任意一个数x,最多会有一个大于sqrt(x)的质因子
}
}
for(int i=1;i<=200000;i++)
sort(k[i].begin(),k[i].end());
long long answer=1;
for(int i=1;i<=200000;i++)
{
if(factor[i]==n-1)
answer*=quick_pow(i,k[i][0]);//处理ki=0只出现一次的情况
else if(factor[i]==n)
answer*=quick_pow(i,k[i][1]);//处理ki=0没有出现的情况
}
printf("%lld",answer);
}
后记
其实这个代码可以改进的地方可以很多,可以实现筛出
2
e
5
2e5
2e5以内的质数再去做操作之类的…
居然错过了这个Mathy的div2场,痛失回到1500的机会 (大误) 。
DrGilbert 2020.5.13