Cod sursa(job #2244698)

Utilizator nurof3nCioc Alex-Andrei nurof3n Data 23 septembrie 2018 14:52:38
Problema Fractii Scor 100
Compilator cpp Status done
Runda Arhiva de probleme Marime 1.58 kb
#include <fstream>

using namespace std;

ifstream in("fractii.in");
ofstream out("fractii.out");

const int N_MAX = 1000000;

int totient[N_MAX + 1]; //indicatorul lui Euler

///O(N*logN)
void compute_totient(int N) {
//  initializare
    totient[1] = totient[2] = 1;
    for(int i = 3; i <= N; i++)
        totient[i] = i - 1;
    /**
                  TEOREMA
    ---------------------------------------
    n = suma tuturor totient(d), unde d | n
    */
//  folosim ideea de la ciur si teorema precedenta:
    for(int i = 2; i <= N; i++) //deja stim valoarea totient[1...i]
        for(int j = 2 * i; j <= N; j += i)  //scadem pe totient[i] din totient[k * i]
            totient[j] -= totient[i];
}

///O(NloglogN)
void compute_totient2(int N) {
//  initializare
    for(int i = 1; i <= N; i++)
        totient[i] = i; //semnifica faptul ca nu e calculat, adica ca este prim
    /**
                            TEOREMA
    --------------------------------------------------------
    n = p1 ^ a1 * p2 ^ a2 * ... * pk ^ ak
    totient(n) = n * (1 - 1/p1)(1 - 1/p2) * ... * (1 - 1/pk)
    */
//folosim ideea de la ciur si teorema precedenta:
    for(int i = 2; i <= N; i++)
        if(totient[i] == i) //nu este calculat, deci i este prim
            for(int j = i; j <= N; j += i)  //iteram prin toti multiplii lui i, inclusiv i
                totient[j] -= totient[j] / i;
}
int main() {
    int N;
    in >> N;

    compute_totient2(N);

    long long sol = 1;
    for(int i = 2; i <= N; i++)
        sol += 2 * totient[i];
    out << sol;

    return 0;
}