Cod sursa(job #234712)

Utilizator mist000000 mist Data 21 decembrie 2008 20:14:56
Problema Fractii Scor 100
Compilator cpp Status done
Runda Arhiva de probleme Marime 1.5 kb
/*
 * http://mathworld.wolfram.com/TotientFunction.html
 * http://infoarena.ro/forum/?topic=33.0
 *
 * p - prime number
 * t(p^e) = (p - 1) * p^(e - 1)
 * p - prime number, p does not divide a
 * t(p^e * a) = t(p^e) * t(a) = (p - 1) * p^(e - 1) * t(a)
 *
 * This way we can easily find t(n+1) knowing a single prime divisor of n+1
 * and all t(1), t(2), ... t(n)
 */

#include <iostream>
#include <fstream>

using namespace std;

int main()
{
	long N;
	ifstream in("fractii.in");
	in >> N;
	in.close();

	long *firstDivisor = new long[N + 1];
	memset(firstDivisor, 0, (N + 1) * sizeof(*firstDivisor));
	long long *totient = new long long[N + 1];
	totient[1] = 1;

	for (long i = 2; i <= N; i++) {
		long m = i + i;
		while (m <= N) {
			if (firstDivisor[m] == 0)
				firstDivisor[m] = i;
			m += i;
		}
		if (firstDivisor[i] == 0) {
			totient[i] = i - 1;
		}
		else {
			long pe = firstDivisor[i];
			int e = 1;
			while (i % (pe * firstDivisor[i]) == 0) {
				pe *= firstDivisor[i];
				e++;
			}
			if (pe == i) {
				// i is power of a prime number
				totient[i] = (firstDivisor[i] - 1)
					* pe / firstDivisor[i];
			}
			else {
				totient[i] = totient[pe] * totient[i / pe];
			}
		}
	}

	delete[] firstDivisor;

	long long solutions = 1;	// the fraction 1/1
	// totient only has relative primes smaller than i
	// count both (i / totient[i]) and (totient[i] / i)
	for (long i = 2; i <= N; i++)
		solutions += 2 * totient[i];

	delete[] totient;

	ofstream out("fractii.out");
	out << solutions << endl;
	out.close();

	return 0;
}