Codeforces Round 837 (Div. 2)
C. Hossam and Trainees
思路:
题目翻译一下,其实就是如果两个数的最大公因数不等于 1 1 1,这两个数就可以配对成功。
所以一种想法就是把每个数质因数分解,只要其中有一对数有重复的质因数,就可以配对成功,否则一对都没有就配对失败。找重复的质因数可以用set,把每个数包含的质因数尝试放入set,如果已经存在,则说明和前面某个数有重复质因数。
质因数分解朴素想法是用筛筛出来,但是空间存不下,而且也会超时。考虑到一个 ≤ 1 0 9 \le 10^9 ≤109 的数大部分质因数都是 ≤ 1 0 9 \le\sqrt {10^9} ≤109 的,最多只有一个质因数 > 1 0 9 \gt \sqrt {10^9} >109,所以我们可以把 ≤ 1 0 9 \le\sqrt {10^9} ≤109 的所有质数筛出来,然后枚举质数去验证是不是这个数的因数,这样就可以用 1 0 9 l n 1 0 9 ≈ 3 ∗ 1 0 3 \dfrac{\sqrt{10^9}}{ln{\sqrt{10^9}}}\approx3*10^3 ln109109≈3∗103 的空间和时间来分解出一个数的质因数(3042个质数)。
时间复杂度是分解的复杂度加上维护set的复杂度,大概是 O ( n ∗ 1 0 9 l n 1 0 9 + n ∗ l o g 2 ) O(n*\dfrac{\sqrt{10^9}}{ln{\sqrt{10^9}}}+n*log^2) O(n∗ln109109+n∗log2),运算次数大概是 1 0 8 10^8 108 量级,时限有两秒,可以通过。
code:
#include <iostream>
#include <cstdio>
#include <cmath>
#include <set>
using namespace std;
const int maxn=1e5+5;
const int inf=1e9;
const int sq=sqrt(1e9)+5;
int T,n,a[maxn];
bool vis[maxn];
int prime[maxn],cnt;
void Eular(int n){
vis[1]=true;
for(int i=2;i<=n;i++){
if(!vis[i])
prime[++cnt]=i;
for(int j=1,p=prime[1];j<=cnt && i*p<=n;p=prime[++j]){
vis[i*p]=true;
if(i%p==0)break;
}
}
}
bool check(){
set<int> S;
for(int i=1;i<=n;i++){
for(int j=1,p=prime[1];j<=cnt && p<=a[i];p=prime[++j]){
if(a[i]%p!=0)continue;
while(a[i]%p==0)a[i]/=p;
if(S.find(p)==S.end())S.insert(p);
else return true;
}
if(a[i]>1){
if(S.find(a[i])==S.end())S.insert(a[i]);
else return true;
}
}
return false;
}
int main(){
cin.tie(0)->sync_with_stdio(false);
Eular(sq);
cin>>T;
while(T--){
cin>>n;
for(int i=1;i<=n;i++)cin>>a[i];
puts((check())?"YES":"NO");
}
return 0;
}