Cod sursa(job #1184574)

Utilizator crucerucalinCalin-Cristian Cruceru crucerucalin Data 13 mai 2014 11:06:10
Problema Ciurul lui Eratosthenes Scor 0
Compilator cpp Status done
Runda Arhiva educationala Marime 2.53 kb
/**
 * Link infoarena: http://www.infoarena.ro/problema/sireturi
 **
 * Foloseste observatia ca numarul cerut este numarul de divizori ai lui (n-1)!
 * la patrat, deci trebuie folosita o metoda eficienta de calculare a numarului
 * de divizori pentru un numar foarte mare.
 **/
#include <cstdio>
#include <cmath>

const int MOD = 9901;
const int NMAX = 7501;
const int NMAX_DIV = 950;

unsigned char V[NMAX / 2 / 8 + 1];

// vectorul in care tin numerele prime
int vec[NMAX_DIV + 1];

// pe fact[i][j] se afla un numar P care spune de cate ori intra
// al j-lea numar prim in descompunerea lui i.
int fact[NMAX][NMAX_DIV + 1];

// sumele precalculate
int sums[NMAX][NMAX_DIV + 1];

void ciur()
{
	int i, j, NMAX_DIV = 1;

	for (i = 1; ((i * i) << 1) + (i << 1) < NMAX; i += 1) {
		if ((V[i >> 3] & (1 << (i & 7))) == 0) {
			for (j = ((i * i) << 1) + (i << 1);
			     (j << 1) + 1 < NMAX; j += (i << 1) + 1) {
				V[j >> 3] |= (1 << (j & 7));
			}
		}
	}
}

int main()
{
	freopen("sireturi.in", "r", stdin);
	freopen("sireturi.out", "w", stdout);
	
	int T, n, cnt = 1;

	ciur();

	/* Pastrez in vec numerele prime. */
	vec[0] = 2;
	for (int i = 1; (i << 1) + 1 < NMAX; i++)
		if ((V[i >> 3] & (1 << (i & 7))) == 0)
			vec[cnt++] = (i << 1) + 1;



	int j, k;

	/* Pun 1 pe pozitiile care coresund numerelor prime deoarece acestea se
	 * descompun ca ele * 1 iar 1 nu mai trebuie trecut. */
	for (j = 0; j < NMAX_DIV; ++j)
		fact[vec[j]][j] = 1;

	/* Calculez factorizarea fiecarui numar pana la NMAX. */
	for (j = 4; j < NMAX; ++j) {
		/* Daca numarul este prim, am calculat mai sus factorizarea, e chiar
		 * numarul in sine. */
		if (j % 2 && (V[((j-1)/2) >> 3] & (1 << (((j-1)/2) & 7))) == 0)
			continue;

		/* Pastrez intr-o variabila, pentru ca se va modifica. */
		int tmp = j;
		/* Parcurg toate numerele prime, sau pana cand numarul meu a devenit
		 * 1, adica i-am determinat toti divizorii. */
		for (k = 0; k < NMAX_DIV && tmp > 1; ++k)
			/* Daca se imparte la numarul prim curent, cat timp se imparte,
			 * il impartim la el si incrementam pozitia asociata din
			 * matrice. */
			if (!(tmp % vec[k]))
				while (!(tmp % vec[k])) {
					tmp /= vec[k];
					fact[j][k]++;
				}
	}

	sums[0][NMAX_DIV] = sums[1][NMAX_DIV] = 1;
	for (j = 2; j < NMAX; ++j) {
		unsigned long long sol = 1;
		for (k = 0; k < NMAX_DIV; ++k) {
			sums[j][k] = sums[j-1][k] + fact[j][k];
			sol *= (2 * sums[j][k] + 1);
			sol %= MOD;
		}
		sums[j][NMAX_DIV] = sol % MOD;
	}

	scanf("%d", &T);
	for (int i = 0; i < T; ++i) {
		scanf("%d", &n);
		printf("%d\n", sums[n-1][NMAX_DIV]);
	}



	return 0;
}