Cod sursa(job #916429)

Utilizator romircea2010FMI Trifan Mircea Mihai romircea2010 Data 16 martie 2013 15:02:02
Problema Suma si numarul divizorilor Scor 100
Compilator cpp Status done
Runda Arhiva educationala Marime 3.03 kb
/**
    Suma si numarul divizorilor:
    daca descompunerea in factori primi a lui n este
    n = (p1 ^ d1) * (p2 ^ d2) * ... * (pk ^ pk) atunci numarul divizorilor este
    NR = (d1 + 1) * (d2 + 1) * ... * (dk + 1);
    si suma divizorilor este
    SUMA = (1 + p1 + p1^2 + ... + p1^d1) * (1 + p2 + p2^2 + ... + p2^d2) * ... * (1 + pk + pk^2 + ... + pk^dk) =
    = produs de progresii geometrice cu primul termen 1 si ratia p1, p2, ... ,pk =
    (p1 ^ (d1+1) - 1)/(p1 - 1) * (p2 ^ (d2+1) - 1)/(p2 - 1) * ... * (pk ^ (dk+1) - 1)/(pk - 1)

*/
#include <iostream>
#include <fstream>
#include <cstdio>
#include <algorithm>
#define milion 1000000
#define MOD 9973

using namespace std;

bool viz[1000010];
long long ciur[80000];
int nciur, sol1, sol2, na;
// sol1 = numarul divizorilor;
// sol2 = suma divizorilor % MOD

inline void CreareCiur()
{
    /// numerele prime pana la 10 ^ 6 deoarece numerele date sunt pana in 10^12
    int i, j, doii;
    viz[0] = viz[1] = true;
    ciur[++nciur] = 2;
    for (i = 3; i<=milion; i += 2)
        if (viz[i] == false)
        {
            ciur[++nciur] = i;
            if (i<=1000)
                for (j = i*i, doii = 2*i;j <= milion; j += doii)
                    viz[j] = true;
        }
}

inline int Putere (int x, int y)
{
    int put = 1;
    while (y)
    {
        if (y&1)
        {
            put = (put*(x%MOD))%MOD;
            y--;
        }
        y = y>>1;
        x = ((x%MOD)*(x%MOD))%MOD;
    }
    put = put - 1;
    if (put < 0)
        put = put + MOD;
    return put;
}

inline int InversModular(int x)
{
    int y = MOD - 2, put = 1;
    while (y)
    {
        if (y&1)
        {
            put = (put*(x%MOD))%MOD;
            y--;
        }
        y = y>>1;
        x = (x%MOD)*(x%MOD)%MOD;
    }
    return put;
}


inline void Solve(long long nr)
{
    sol1 = sol2 = 1;
    int i, div, put;
    i = 1;
    while (i <= nciur && ciur[i]*ciur[i] <= nr)
    //while (nr!=1)
    {
        div = ciur[i];
        i++;
        if (nr % div == 0)
        {
            put = 0;
            while (nr % div == 0)
            {
                put++;
                nr/=div;
            }
            sol1 = sol1 * (put + 1);
            //sol2 = sol2 * (div ^ (put+1) - 1) / (div - 1);
            sol2 = ((sol2 * Putere (div, put+1)) % MOD * InversModular (div - 1)) % MOD;
            // Putere (a, b) = (a^b - 1) % MOD
            // InversModular (a) = inversul modular al lui a pentru modulo = MOD
            // InversModular (a) = (a^(MOD-2)) % MOD dupa mica teorema a lui Fermat
        }
    }
    if (nr!=1LL)
    {
        sol1 *= 2;
        sol2 = ((sol2 * Putere (nr, 2)) % MOD * InversModular (nr - 1)) % MOD;
    }

}

int main()
{
    CreareCiur();
    ifstream f ("ssnd.in");
    ofstream g ("ssnd.out");
    int t;
    f>>t;
    long long nr;
    while (t--)
    {
        f>>nr;
        Solve(nr);
        g<<sol1<<" "<<sol2<<"\n";
    }
    f.close();
    g.close();
    return 0;
}