中石油 问题 B: 赛博朋克(数学)
题意:
n个数,先两两求最小公倍数,然后再对公倍数求最大公因数.
思路:
将题意整合一下就是 把这些数分解质因子,然后针对每个质因子,第二小的就是这个质数的代价.
怎么得来的那?
因为我们先求最小公倍数,在求最大公因数,那么我们找到两个针对某一质数,代价最小的两个数,这个地方有点难理解,
假设这些数中有 8,9,40,66,80,34,70, 然后我们针对质数2来找到代价最小的两个数
原数8 9 40 66 80 34 70
针对质数2的代价8 0 8 2 16 2 2
所以我们看出最小的两个代价是0和2
所以求出的最小公倍数就有代价2
,然后在求最大公因数,因为我们找出的是最小的两个代价,所以其他的最小公倍数的代价,都大于或等于2,所以最后求最大公因数就是2
这是光针对质数2了来讲的,针对其他的质数也一样
知道这之后就是维护时间复杂度了,因为2e5中的质数将近有2e4
个n又是1e5
所以枚举所有质数很显然不现实.
所以我们可以先筛出\(\sqrt{2e5}\)之内的素数,剩下的,我们分解质因数时,剩的肯定就是一个素数,那么我们将其加入到素数列表中即可.
还有就是维护第二小的质数代价,我们就得看看0代价的数量,如果0代价的数量大于等于2,那么这个质数就不会产生代价.
ll t;
ll n, k, cnt;
ll a[maxn];
bool isprime[maxn];
ll prime[maxn], dis[maxn], vis[maxn];
void p()
{
for(int i = 2; i <= sqrt(2e5 + 10); i++)
{
if(!isprime[i]) prime[++cnt] = i;
for(int j = 1; j <= cnt && i * prime[j] <= sqrt(2e5 + 10) ; j++)
{
isprime[i * prime[j]] = 1;
if(i % prime[j] == 0) break;
}
}
}
void solve()
{
p();
scanf("%lld", &n);
ll maxx = 0;
for(int i = 1; i <= n; i++)
{
scanf("%lld", &a[i]);
maxx = max(maxx, a[i]);
for(int j = 1; j <= cnt; j++)
{
ll num = 1;
while(a[i] % prime[j] == 0)
{
a[i] /= prime[j];
num = num * prime[j];
}
if(num != 1) dis[num]++, vis[prime[j]]++;
if(a[i] == 1) break;
}
if(a[i] > 1) prime[++cnt] = a[i], dis[a[i]]++, vis[a[i]]++;
}
ll ans = 1;
for(int i = 1; i <= cnt; i++)
{
if(n - vis[prime[i]] >= 2) continue;
ll num = 2 - (n - vis[prime[i]]);
for(int j = prime[i]; j < maxx; j *= prime[i])
{
num -= dis[j];
if(num <= 0)
{
ans = ans * j;
break;
}
}
}
printf("%lld\n",ans);
}