Cod sursa(job #51611)

Utilizator scapryConstantin Berzan scapry Data 15 aprilie 2007 18:17:40
Problema Frac Scor 100
Compilator cpp Status done
Runda Arhiva de probleme Marime 2.08 kb
#include <assert.h>
#include <stdio.h>

enum { maxfactor = 14, maxfactorcomb = 1 << maxfactor };

long long n, wanted;
long long bottom, top, mid;
long long prime[maxfactor], primes;
long long factor[maxfactorcomb], factors;

int k, count_used;
long long product;

void check(long long p)
{
	if(n % p == 0) prime[primes++] = p;

	while(n % p == 0)
		n /= p;
}

void calc_primes()
{
	check(2);

	for(long long p = 3; p * p < n; p += 2)
		check(p);

	if(n != 1) check(n);

	assert(primes != 0);
}

void bkt()
{
	if(k == primes)
	{
		if(count_used != 0) //screw 1
		{
			if(count_used % 2 == 1) factor[factors] = -product;
			else factor[factors] = product;
			factors++;
		}
		return;
	}
	assert(k >= 0 && k < primes);

	//don't use
	k++;
	bkt();
	k--;

	//use
	count_used++;
	product *= prime[k];
	k++;
	bkt();
	k--;
	assert(product % prime[k] == 0);
	product /= prime[k];
	count_used--;
}

void calc_factors()
{
	product = 1;
	bkt();
}

long long attempt()
{
	long long work = mid;

	for(int i = 0; i < factors; i++)
	{
		work += mid / factor[i];
		if(factor[i] < 0) work++;
		else work--;
	}

	return work - 1;
}

void bsearch()
{
	long long ans;
	int i;

	bottom = 1;
	top = 1ll << 61; //better bounds?

	while(true)
	{
		assert(bottom < top);
		mid = (bottom + top) / 2;

		//now fix it
		while(mid >= bottom)
		{
			for(i = 0; i < primes; i++)
				if(mid % prime[i] == 0) break;

			if(i == primes) //relatively prime, as needed
				break;

			mid--;
		}
		
		if(mid == bottom - 1)
		{
			mid = (bottom + top) / 2 + 1;

			while(mid <= top)
			{
				for(i = 0; i < primes; i++)
					if(mid % prime[i] == 0) break;

				if(i == primes) //passed
					break;

				mid++;
			}

			assert(mid <= top);
		}

		ans = attempt();

		if(ans < wanted) //go higher
			bottom = mid + 1;
		else if(ans > wanted) //go lower
			top = mid;
		else //just right
			break;
	}
}

int main()
{
	FILE *f = fopen("frac.in", "r");
	if(!f) return 1;
	fscanf(f, "%lld%lld", &n, &wanted);
	fclose(f);
	f = fopen("frac.out", "w");
	if(!f) return 1;

	calc_primes();
	calc_factors();
	bsearch();

	fprintf(f, "%lld\n", mid);
	fclose(f);
	return 0;
}