Hörmətli#12366

Hörmətli (Həll təhlili)

Problem Müəllifi:

Tamzid Alahi (tamzid01)

Hazırlayan:

Tamzid Alahi (tamzid01)

Redaktə edən:

Hasan Saleh (MathModel)

Həll

Əsas müşahidə odur ki, bir tam ədəd yalnız a_i və a_j ədədləri -nin çoxluqları olduqda (a_i, a_j) cütünün ortaq böləni olur. -ni massiv -da -nin çoxluğu olan elementlərin sayı kimi təyin etsək, onda -nin \gcd(a_i, a_j)-ni bölən cütlərin ümumi sayı aşağıdakı kimi verilir:

\binom{C(g)}{2} = \frac{C(g) \times (C(g) - 1)}{2}

Lakin bu dəyər -nin böləni olan hər cütü sayır, mütləq ən böyük ortaq bölən deyil. Məsələn, və ya olan bir cüt üçün sayda daxil ediləcəkdir. GCD-nin dəqiq olduğu cütləri ayırmaq üçün, onun çoxluqlarına aid cütləri çıxarmalıyıq. Biz bunu enən süzgəc istifadə edərək həyata keçiririk. İlk öncə, giriş oxuyarkən saylarımızı tez bir zamanda yeniləmək üçün 10^5-ə qədər bütün ədədlərin bölənlərini əvvəlcədən hesablayırıq. Hər a_i üçün, onun hər bir böləni üçün sayğacı artırırıq. Biz yalnız C(g) \ge 2 olan dəyərləri ilə maraqlanırıq, çünki GCD ən azı iki ədəd tələb edir. Sonra -ni GCD-si dəqiq olan cütlərin sayı kimi təyin edirik. f[g] = \binom{C(g)}{2} ilə başlayırıq. 10^5-dən -ə qədər iterasiya edərək, -ni emal etdiyimiz zaman, artıq onun bütün çoxluqları 2g, 3g, 4g, \dots üçün sayları tamamlanmış olur. Belə bir çoxluq üçün, -ni -dən çıxarırıq. Bu proses effektiv şəkildə -ni "təmizləyir", belə ki, yalnız GCD-si -dən nə daha böyük, nə də daha kiçik olan cütlərin sayını ehtiva edir.

f(g) = \binom{C(g)}{2} - \sum_{k=2}^{\lfloor MAX/g \rfloor} f(k \cdot g)

Bu çıxarışdan sonra, əgər f[g] > 0-dırsa, demək ki, massivdə -nin GCD-si olan ən azı bir cüt var və biz ümumi cavabımızı artırırıq. Hesablamanın mürəkkəbliyi bölənlərin əvvəlcədən hesablanması və süzgəc ilə müəyyən edilir, nəticədə hər test halı üçün effektiv O(A \log A + \sum d(a_i)) olur.

#include <bits/stdc++.h>
using namespace std;
#define int long long

const int MAXA=100005;
vector<int> divs[MAXA];
int cnt[MAXA],f[MAXA];

void pre(){
    for(int i=1;i<MAXA;i++){
        for(int j=i;j<MAXA;j+=i){
            divs[j].push_back(i);
        }
    }
}

void solve(){
    int n;cin>>n;
    vector<int>used;
    for(int i=0;i<n;i++){
        int x;cin>>x;
        for(int d:divs[x]){
            if(!cnt[d])used.push_back(d);
            cnt[d]++;
        }
    }
    vector<int>cand;
    for(int d:used){
        if(cnt[d]>=2)cand.push_back(d);
    }
    sort(cand.rbegin(),cand.rend());
    int ans=0;
    for(int d:cand)f[d]=(cnt[d]*(cnt[d]-1))/2;
    for(int m:cand){
        if(f[m]>0){
            ans++;
            for(int d:divs[m]){
                if(d!=m&&cnt[d]>=2)f[d]-=f[m];
            }
        }
    }
    cout<<ans<<"\n";
    for(int d:used){
        cnt[d]=0;
        f[d]=0;
    }
}

signed main(){
    ios::sync_with_stdio(0);
    cin.tie(0);
    pre();
    int t;cin>>t;
    while(t--)solve();
    return 0;
}