Cod sursa(job #417211)

Utilizator MarcvsHdrMihai Leonte MarcvsHdr Data 14 martie 2010 10:47:46
Problema Numere 2 Scor 95
Compilator cpp Status done
Runda Arhiva de probleme Marime 4.81 kb
# include <stdio.h>
# include <string.h>

# define MAXN 150

# define BAZA 10

# define NRCFB 1

# define DEBUG

typedef struct NUMAR{
	long int len,v[MAXN+1];
}NUMAR;

NUMAR nrp,sol,unu;
long int sole;

long int nrcf(long int a)
{
	long int sol=0;
	do{
		sol++;
		a/=10;
	}while (a);
	return sol;
}


void scrie_numar(FILE *g, NUMAR& a)
{
	long int i,j;
	fprintf(g,"%ld",a.v[a.len]);
	for (i=a.len-1;i>=1;i--)
		{
		for (j=nrcf(a.v[i])+1;j<=NRCFB;j++) fprintf(g,"0");
		fprintf(g,"%ld",a.v[i]);
		}
	fprintf(g,"\n");
}

void normalizeaza_adunare(NUMAR& a)
{
	long int i;
	for (i=1;i<=a.len-1;i++)
		{
		a.v[i+1]+=a.v[i]/BAZA;
		a.v[i]%=BAZA;
		}
	while (a.v[a.len]>=BAZA)
		{
		a.v[a.len+1]=a.v[a.len]/BAZA;
		a.v[a.len]%=BAZA;
		a.len++;
		}
}


void aduna(NUMAR &dest, NUMAR &a, NUMAR& b)
{
	long int i,min,max;
	min = a.len<b.len ? a.len : b.len;
	max = a.len>b.len ? a.len : b.len;
	for (i=1;i<=min;i++) dest.v[i]=a.v[i]+b.v[i];
	for (i=min+1;i<=a.len;i++) dest.v[i]=a.v[i];
	for (i=min+1;i<=b.len;i++) dest.v[i]=b.v[i];
	dest.len=max;
	normalizeaza_adunare(dest);
}

void inmulteste(NUMAR& dest, NUMAR& a, NUMAR& b)
{
	long int i,j;
	dest.len=a.len+b.len-1;
	for (i=1;i<=dest.len;i++)
		dest.v[i]=0;
	for (i=1;i<=a.len;i++)
		for (j=1;j<=b.len;j++)
			dest.v[i+j-1]+=a.v[i]*b.v[j];
	normalizeaza_adunare(dest);
}

void imparte_la_nr(NUMAR& a, int div)
{
	long int remainder = 0, i;
	for (i=a.len;i>=1;i--)
		{
		remainder = remainder*BAZA + a.v[i]; 
		a.v[i] = remainder/div;
		remainder = remainder%div;
		}
	while (a.v[a.len]==0 && a.len>1)
		a.len--;
	//scrie_numar(stdout,a);
}

void normalizeaza_scadere(NUMAR& a)
{
	long int i;
	for (i=1;i<=a.len-1;i++)
		while (a.v[i]<0)
			{
			a.v[i]+=BAZA;
			a.v[i+1]--;
			}
	while (a.v[a.len]==0 && a.len>1)
		a.len--;
}

void scade_numar(NUMAR& a, int scad)
{
	a.v[1]-=scad;
	//printf("Inainte de scadere\n");
	//scrie_numar(stdout,a);
	normalizeaza_scadere(a);
}

void aduna_numar(NUMAR& a, int adun)
{
	a.v[1]+=adun;
	normalizeaza_adunare(a);
}

void make_1(NUMAR& a)
{
	a.len = 1;
	a.v[1] = 1;
}

void make_0(NUMAR &a)
{
	a.len = 1;
	a.v[1] = 0;
}

int compara(NUMAR& a, NUMAR &b)
{
	long int i;
	if (a.len<b.len) return -1;
	if (a.len>b.len) return 1;
	for (i=a.len;i>=1;i--)
		{
		if (a.v[i]<b.v[i]) return -1;
		if (a.v[i]>b.v[i]) return 1;
		}
	return 0;
}


void scrie(NUMAR &baza, long int exponent)
{
	FILE *g=fopen("numere2.out","w");
	scrie_numar(g,baza);
	fprintf(g,"%ld\n",exponent);
	fclose(g);
}

void citire(NUMAR& a)
{
	char buffer[120];
	FILE *f=fopen("numere2.in","r");
	fscanf(f,"%s",buffer+1);
	fclose(f);
	char c;
	a.len=0;
	long int dig,i,n=strlen(buffer+1);
	for (i=1;i<=n/2;i++)
		{
		c=buffer[i];
		buffer[i]=buffer[n-i+1];
		buffer[n-i+1]=c;
		}
	char *p=buffer;
	do{
		a.len++;
		a.v[a.len]=0;
		for (i=1,dig=1;i<=NRCFB && p[i];i++,dig*=10)
			a.v[a.len]+=(p[i]-'0')*dig;
		if (p[i]) p+=NRCFB;
		else break;
	} while (1);
}

void ridica_la_putere(NUMAR a, long int exp, NUMAR &sol)
{
	if (exp==0)
		{
		sol = unu;	
		return;
		}
	NUMAR half,tempsol;
	ridica_la_putere(a,exp/2,half);
	inmulteste(tempsol,half,half);
	if (exp%2==1) 
		{
		inmulteste(sol,tempsol,a);
		}
	else
		{
		sol=tempsol;
		}
}

long int nrcifre(NUMAR& n, long int exp)
{
	return (n.len-1)*exp;
}

NUMAR searchbin(NUMAR& li, NUMAR& lf, long int exp, NUMAR& newlf)
{
	NUMAR m,power;
	int comparatie;
	while (compara(li,lf) == -1)
		{

		aduna(m,li,lf);		
		imparte_la_nr(m,2);
//TODO
//		printf("\n");
//		printf("	LI: ");scrie_numar(stdout,li);
//		printf("	LF: ");scrie_numar(stdout,lf);
//		printf(" 	M : ");scrie_numar(stdout,m);
//		getchar();

//debug!
		//verifica intai grosier daca m^exp are mai multe cifre decat nrp
		if (nrcifre(m,exp)>nrp.len)
			{
//			printf("GO LEFT FAST\n");
			lf = m;
			scade_numar(lf,1);
			continue;
			}
		ridica_la_putere(m,exp,power);
		comparatie = compara(power,nrp);
		if (comparatie == 0) 
			{
			newlf=m;
			return m;
			}
		if (comparatie == -1) 
			{
//			printf("GO RIGHT\n");
			li = m;
			aduna_numar(li,1);
			}
		if (comparatie == 1)
			{
//			printf("GO LEFT\n");
			lf = m;
			scade_numar(lf,1);
			}
		}
	if (compara(li,lf)==0)
		{
		m=li;
		ridica_la_putere(m,exp,power);
		comparatie = compara(power,nrp);
		if (comparatie == 0) 
			{
			newlf=m;
			return m;
			}
		}
	newlf = lf;
	m.len = -1;
	return m;
}
		

void calculeaza()
{
	sol=nrp;
	sole=1;
	NUMAR solloc,li,lf,newlf;
	solloc.len = -1;
	make_1(unu);
	long int i;	

	lf = sol;
	for (i=2;i<=332;i++)
		{

		//printf("Acum cautam o solutie binara pentru exponentul %ld --- ",i);

		li = unu;
		solloc = searchbin(li,lf,i,newlf); //cautam binar un numar care ridicat la puterea i sa dea tocmai nrp
		lf = newlf;
		if (solloc.len != -1)
			{
			sol = solloc;
			sole = i;
			}

		/*if (solloc.len != -1)
			printf("Exista!\n");
		else 
			printf("Wrong again :-<\n");
		*/
		}
}

int main()
{
	citire(nrp);
	calculeaza();
	scrie(sol,sole);
	return 0;
}