Cod sursa(job #2534196)

Utilizator ArkhamKnightyMarco Vraja ArkhamKnighty Data 30 ianuarie 2020 10:46:55
Problema Pairs Scor 0
Compilator cpp-64 Status done
Runda Arhiva de probleme Marime 3.59 kb
#include <fstream>
#include <bitset>

using namespace std;

const int VMAX = 1000001;

int n, xMax;

bitset<VMAX> M;
///Vector caracteristic al multimii de numere distincte M
///M[i] = 1 <==> i apartine multimii M

unsigned char nrdiv[VMAX];
///nrdiv[i] = cate numere prime distincte apar in descompunerea
///           in factori a lui i

bitset<VMAX> ciurp;
///Vector caracteristic al numerelor pentru care descompunerea
///in factori nu are factori primi distincti, adica:
///
///ciurp[i] = 1 <==> i are un divizor prim la o putere >= 2
///                 (i se divide cu patratul unui numar prim)

/*
    Ideea este sa ca am numarul TOTAL de imperecheri - care este n * (n-1) / 2, adica toate cu toate,
dar nu toate aceste combinatii sunt permise
    Astfel, noi vom elimina din numarul total combinatiile nepermise
    Luam un numar prim, vedem cati multiplii are in sirul nostru, calculam numarul de combinatii intre ei
    care este nr * (nr - 1) / 2 si scadem numarul acesta din numarul total de combinatii

    ATENTIE

    Daca exista un numar compus, care mai multi divizori primi in sir, acesta va fi scazut de mai multe ori decat
    este necesar.
    De aceea, ca sa putem scadea un numar cu multiplii lui, trebuie sa aiba numar IMPAR de divizori
*/

ifstream cin("pairs.in");
ofstream cout("pairs.out");

/*void citire()
{
    int x;
    cin >> N;

    for ( int i = 1; i <= N; i++ )
        cin >> x, M[x] = 1,
        xMax = max(xMax, x);
}

int main()
{
    citire();
    long long sol = 1LL * N * ( N - 1 ) / 2;

    for ( int i = 2; i <=  xMax; i++ )
    {
        if ( nrdiv[i] == 0 )
        {
            ///Crestem numarul factorilor primi pentru numerele
            ///divizibile cu i
            for ( int j = i; j <= xMax; j += i )
                nrdiv[j]++;
        }

        //
        if ( ciurp[i] == 0 )
        {
            ///Marcam toti multiplii de i * i
            long long ii = 1LL * i * i;

            for ( long long jj = ii; jj <= xMax; jj += ii )
                ciurp[jj] = 1;

            //
            ///Determinam cate dintre numerele i, 2*i, 3*i,...,[xMax/i]*i
            ///apartin multimii M
            long long rez = 0;

            for ( int j = i; j <= xMax; j += i )
                if ( M[j] == 1 )
                    rez++;

            //
            rez = rez * ( rez - 1 ) / 2; // calculam numarul de combinatii facute de un numar cu toti multiplii lui

            ( !(nrdiv[i] & 1) ) ? // verificam numarul de divizori ca sa vedem daca il adunam sau il scadem
                sol += rez : sol -= rez;
        }
    }

    cout << sol;
    return 0;
}*/

void citire()
{
    int x;
    cin >> n;

    for(int i = 1 ; i <= n ; i++)
        cin >> x, M[x] = 1, xMax = max(xMax, x);
}

void rez()
{
    long long sol = (long long) n * (n - 1) >> 1;

    for(int i = 2 ; i <= xMax ; i++)
    {
        if(!nrdiv[i])
        {
            for(int j = i * i ; j <= xMax ; j += i)
                nrdiv[j]++;

            nrdiv[i]++;
        }

        if(!ciurp[i])
        {
            long long ii = (long long) i * i;

            for(long long jj = ii ; jj <= xMax ; jj += ii )
                ciurp[jj] = 1;

            long long rez = 0;


            for ( int j = i; j <= xMax; j += i )
                if ( M[j] == 1 )
                    rez++;


            rez = (rez * (rez - 1) >> 1 );

            ( !(nrdiv[i] & 1)) ?
                sol += rez : sol -= rez;

        }
    }

    cout << sol;

}

int main()
{
    citire();
    rez();
}