写在前面
笔者是一名十八线蒟蒻ACMer,文中可能会有多处错误与疏漏,欢迎指出。
原题题面
原题地址
时间:3 seconds
空间:256M
For the multiset of positive integers
, define the Greatest Common Divisor (GCD) and Least Common Multiple (LCM) of s as follow:
is the maximum positive integer
, such that all integers in
are divisible on
.
is the minimum positive integer
, that divisible on all integers from
.
For example,
and
. Note that for any positive integer
,
.
Orac has a sequence
with length
. He come up with the multiset
, and asked you to find the value of
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
.
The second line contains
integers,
.
Output
Print one integer:
.
InputExample
10
540 648 810 648 720 540 594 864 972 648
OutPutExample
54
题面分析
给你
个数,让你求出两两组合的LCM的GCD。
先放个作者的题解。
注意到
的数字很大,所以暴力一定T飞,因此考虑别的方法。
我想到了质因子分解。
由唯一分解定理可知,一个数可以被分解为
的形式。
LCM可以认为是在每个
之中取较大值,
GCD可以认为是在每个
之中取较小值。
于是我们可以直接考虑将
个数质因子分解,对每个质因子进行处理。
于是,问题就变成如下。
已知数列
,求出
。
我们不妨设
,可以发现,
就是
。
因为两两取最大值中的最小值,一定是
是最小的。
于是我们的步骤如下:
1.对n个数质因子分解。
2.求出每个质因子系数里第二小的。
3.合并求出答案。
这里可以注意几个细节。
如果满足某个
的数字出现了两次及以上,那
,不予考虑。
如果满足某个
的数字出现了一次,那
为最小的不为零的系数。
如果满足某个
的数字没有出现,那
就是第二小的不为零的系数。
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);
}
后记
其实这个代码可以改进的地方可以很多,可以实现筛出
以内的质数再去做操作之类的…
居然错过了这个Mathy的div2场,痛失回到1500的机会 (大误) 。
DrGilbert 2020.5.13