Cod sursa(job #58874)

Utilizator crawlerPuni Andrei Paul crawler Data 7 mai 2007 17:30:30
Problema Numere 2 Scor 0
Compilator cpp Status done
Runda Arhiva de probleme Marime 15.8 kb
#include <stdio.h>
#include <math.h>
#include <cstdlib>
#include <vector>
#include <cmath>
#include <string>
#define base 1000000000
#define base2 ((ull) base * base)
#define KARATSUBA 11111
#define fix(x) {x.resize(x[0]+3); x[x[0]+1]=x[x[0]+2]=0;}
#define ull unsigned long long

using namespace std;

int nrdiv=0;

class BigInt{
public:
      vector <unsigned> a;  
      int semn;         
      BigInt();
      BigInt(long long nr);   
      BigInt(vector<unsigned> b);
      BigInt& operator+=(const BigInt &b);   
      BigInt& operator+=(long long k);       
      friend BigInt operator+(const BigInt &x, const BigInt &y);
      friend BigInt operator-(const BigInt &x, const BigInt &y);
      BigInt& operator*=(int k);
      friend BigInt operator*(const BigInt &x, const BigInt &y);
      friend BigInt operator/(const BigInt &x, const BigInt &y);
      friend BigInt operator%(const BigInt &x, const BigInt &y);
      BigInt& operator/=(int k);
      int operator%(int k);
      friend int operator==(const BigInt &x, const BigInt &y);
      friend int operator!=(const BigInt &x, const BigInt &y);
      friend int operator<(const BigInt &x, const BigInt &y);
      friend int operator<=(const BigInt &x, const BigInt &y);
      friend int operator>(const BigInt &x, const BigInt &y);
      friend int operator>=(const BigInt &x, const BigInt &y);
      void shr(unsigned k);
      void shl(unsigned k);
      void write(FILE *f) const;
      void read(FILE *f);
};

BigInt::BigInt()
{
       semn=0;         
       a.resize(4);
       a[0]=1;         
}

BigInt::BigInt(long long nr)
{
       if (nr<0) semn=-1, nr=-nr; else semn=1;
       if (!nr) semn=0;
       unsigned long long k=nr;
       a.resize(1);
       while (k>=base) a.push_back(k%base), k/=base;
       a.push_back(k);
       a[0]=a.size()-1;
       fix(a);
}

BigInt::BigInt(vector <unsigned> b)
{
      *this=0;
      b.push_back(0);
      int nr=b.size()*32-1;
      while (nr%29) nr--;
      while (nr){
            *this*=(1<<29);  
            //mai baga ceva aici :)
            nr-=29;
      }
}

void BigInt::shr(unsigned k)
{
        if (k>a[0]) k=a[0];
        unsigned i;
        for (i=1; i<=a[0]-k; i++)
            a[i]=a[i+k];
        a[0]-=k;
        if (!a[0]) a[0]=1, a[1]=1;
        fix(a);
}

void BigInt::shl(unsigned k)
{
        unsigned i;
        a[0]+=k;
        a.resize(a[0]+2);
        for (i=a[0]; i>k; i--)
            a[i]=a[i-k];
        memset(&a[1], 0, 4*k);
}

BigInt& BigInt::operator+=(const BigInt &b)
{
     if (this == &b){       //in cazul ca in care fac a+=a;
        unsigned i, n=a[0]+1;
        for (i=1; i<n; i++) 
            a[i]+=a[i];
        for (i=1; i<n; i++)
            if (a[i]>=base) a[i]-=base, a[i+1]++;
        if (a[n]) a[0]++;
        return *this;
     }
     unsigned i, n=b.a[0]+1;
     for (i=1; i<n; ++i)
         if (a[i]+b.a[i]>=base) a[i]+=(b.a[i]-base), a[i+1]++; else a[i]+=b.a[i];
     if (a[n]) n++;
     if (n-1>a[0]) a[0]=n-1;
     fix(a);
     return *this;
}

BigInt operator+(const BigInt &x, const BigInt &y)
{
       if (x.semn==0) return y;
       if (y.semn==0) return x;
       BigInt rez;
       const unsigned *a, *b, *c;
       if (x.semn==y.semn){
          rez.semn=x.semn;
          if (x.a[0]>y.a[0]) a=&x.a[0], b=&y.a[0]; else a=&y.a[0], b=&x.a[0];       
          unsigned n=a[0]+1, m=b[0]+1;
          rez.a.resize(a[0]+2);
          memcpy(&rez.a[0], a, sizeof(unsigned) * (n+1));
          for (unsigned i=1; i<m; i++){
              rez.a[i]+=b[i];
              if (rez.a[i]>=base) rez.a[i]-=base, ++rez.a[i+1];
          }
          unsigned k=m;
          while (rez.a[k]>=base) rez.a[k]-=base, ++k, ++rez.a[k];
          if (rez.a[a[0]+1]) rez.a[0]++;
          fix(rez.a);
          if (rez.a[0]==1 && rez.a[1]==0) rez.semn=0;
          return rez;
       }
       rez.semn=x.semn;
       if (x.semn>=0) a=&x.a[0], b=&y.a[0]; else a=&y.a[0], b=&x.a[0];       
       unsigned i, n, m, ok=1;
       if (b[0]>a[0]) ok=0;
       if (a[0]==b[0])
          for (i=a[0]; i>0; i--){
              if (a[i]!=b[i]){
                 ok=(a[i]>b[i]);
                 break;
              }
          }
       if (!ok) c=a, a=b, b=c, rez.semn=-x.semn;  
       m=b[0]+1;
       rez.a.resize(a[0]+3);
       memcpy(&rez.a[0], a, 4*(a[0]+1));
       for (i=1; i<m; i++){
           if (rez.a[i]>base) rez.a[i]+=base, --rez.a[i+1];
           rez.a[i]-=b[i];
           if (rez.a[i]>base) rez.a[i]+=base, --rez.a[i+1];
       }
       while (rez.a[i]>base) rez.a[i]+=base, ++i, --rez.a[i];
       n=rez.a[0];
       while (n>1 && rez.a[n]==0) --n;
       rez.a[0]=n;
       fix(rez.a);
       if (rez.a[0]==1 && rez.a[1]==0) rez.semn=0;
       return rez;
}

BigInt operator-(const BigInt &x, const BigInt &y)
{
       BigInt a=y;
       a.semn*=-1;          
       return x+a;
}

BigInt& BigInt::operator+=(long long nr)
{
        fix(a);
        if (a.size()<5) a.resize(5);
        ull k = nr, poz=1;
        while (k>=base){
              a[poz]+=k%base;
              k/=base;
              if (a[poz]>=base) a[poz]-=base, ++a[poz+1];
              poz++;
        }
        a[poz]+=k;
        if (a[poz]>=base) a[poz]-=base, ++a[poz+1];
        if (a[a[0]+1]) a[0]++;
        fix(a);
        return *this;
}

BigInt& BigInt::operator*=(int nr)
{
        if (nr<0) semn=-semn, nr=-nr;
        ull num, k=nr;
        unsigned i;
        for (i=a[0]; i>0; i--){
            num=a[i] * k;
            unsigned cat = num/base;
            a[i]=num - (ull)cat*base;
            a[i+1]+=cat;   
            if (a[i]>=base) a[i]-=base, a[i+1]++;
        }
        if (a[a[0]+1]) a[0]++;
        while (a[0]>1 && !a[a[0]]) --a[0];
        fix(a);
        return *this;
}

BigInt operator*(const BigInt &x, const BigInt &y)
{                          
       const unsigned *a, *b;
       if (x.a[0]>y.a[0]) a=&x.a[0], b=&y.a[0]; else a=&y.a[0], b=&x.a[0];       
       unsigned n=a[0]+1, m=b[0]+1, i, j, k;
       unsigned limit=75*n/100;
       if (m>KARATSUBA && m<limit){
          m--; n--;
          BigInt rez, A, B;
          A.a.resize(m+3);
          rez.a.resize(n+m+3);
          const BigInt *C;
          if (x.a[0]>y.a[0]) C=&y; else C=&x;
          A.a[0]=m;
          k=1;
          while (k<=n){
                if (k+m-1>n){
                   A.a[0]=n-k+1; fix(A.a);
                }
                memcpy(&A.a[1], a+k, 4*A.a[0]);
                B=A*(*C);
                for (i=1; i<=B.a[0]; i++){
                    rez.a[i+k-1]+=B.a[i];
                    if (rez.a[i+k-1]>=base) rez.a[i+k-1]-=base, ++rez.a[i+k];
                }
                k+=m;
          }
          n+=m;
          while (n>1 && !rez.a[n]) --n;
          rez.a[0]=n;
          rez.semn=x.semn*y.semn;
          fix(rez.a);
          return rez;
       }
       if (n>KARATSUBA && m>=limit){  //Karatsuba
          BigInt x1, x2, y1, y2, A, B, C;
          unsigned p=(n+m)/4;
          x2.a.resize(p+4);
          x2.a[0]=p;
          memcpy(&x2.a[1], a+1, 4*p);
          x1.a.resize(n-p+4);
          x1.a[0]=n-p-1;
          memcpy(&x1.a[1], a+p+1, 4*(n-p-1));
          y2.a.resize(p+4);
          y2.a[0]=p;
          memcpy(&y2.a[1], b+1, 4*p);
          y1.a.resize(m-p+4);
          y1.a[0]=m-p-1;
          memcpy(&y1.a[1], b+p+1, 4*(m-p-1));
          A=x1*y1;
          B=x2*y2;
          C=(x1+x2)*(y1+y2)-A-B;
          A.shl(2*p);
          memcpy(&A.a[1], &B.a[1], sizeof(unsigned)*2*p);
          C.shl(p);
          A+=C;
          A.semn=x.semn*y.semn;
          fix(A.a);
          return A;
       }
       vector <ull> sol(n+m+1); 
       sol[0]=n+m-3;
       for (i=1; i<m; i++)
           for (j=1, k=i; j<n; ){
               #define W sol[k] += (ull) b[i] * a[j++]; if (sol[k]>=base2) sol[k]-=base2, ++sol[k+2]; k++;
               W W W 
           }
       BigInt rez;
       rez.a.resize(sol[0]+3);
       for (i=0; i<n+m; i++)
           if (sol[i]>=base2) sol[i]-=base2, ++sol[i+2];
       for (i=0; i<n+m; i++){
           unsigned cat=sol[i]/base;
           sol[i+1]+=cat;
           rez.a[i]=sol[i]-cat*(ull)base;
       }
       if (rez.a[rez.a[0]+1]) rez.a[0]++;
       fix(rez.a);
       rez.semn=x.semn * y.semn;
       return rez;
}

BigInt& BigInt::operator/=(int nr)
{
        if (nr<0) semn=-semn, nr=-nr;
        ull num=0;
        const unsigned k=nr;
        for (unsigned i=a[0]; i; i--){
            num=a[i] + num*base;
            a[i]=num/k;
            num%=k;
        }
        while (!a[a[0]] && a[0]>1) a[0]--;
        fix(a);
        if (a[0]==1 && !a[1]) semn=0;
        return *this;
}

int BigInt::operator%(int nr)
{
    ull num=0;
    const unsigned k=nr;
    for (unsigned i=a[0]; i; i--)
        num=(a[i] + num*base)%k;
    return num;
}

BigInt operator/(const BigInt &x, const BigInt &y)
{
       if (x<y) return 0;
       nrdiv+=x.a[0]*y.a[0];
       unsigned n=x.a[0], m=y.a[0];
       BigInt nr=0, cat, rez;
       nr.semn=1; nr.a[0]=0;
       nr.a.resize(m+4);
       rez.a.resize(n+3);
       unsigned i,j;
       for (i=n; i>0; i--){
           nr.a[0]++;
           for (j=nr.a[0]; j>1; j--)
               nr.a[j]=nr.a[j-1];
           nr.a[1]=x.a[i];
           while (nr.a[0]>1 && !nr.a[nr.a[0]]) --nr.a[0];
           nr.semn=1;
           if (nr<y){ rez.a[i]=0; continue; }
           unsigned p,u;
           long double num1=(long double) base * nr.a[m+1] + (long double)nr.a[m];
           long double num2=(long double) y.a[m];
           if (m>1){
                    num1=num1*base + (long double) nr.a[m-1];
                    num2=num2*base + (long double)  y.a[m-1];
           }
           if (m==1) p=(unsigned) (num1/num2); else p=(unsigned) (num1/(num2+1));
           cat=y;
           cat*=p;
           u = (unsigned) round((num1+1)/(num2-0.5));
           if (m==1) u=(unsigned) round((num1+1)/num2);
           if (u>p && cat+y<=nr) cat=cat+y, ++p;
           nr=nr-cat;
           rez.a[i]=p;
       }
       while (n>1 && !rez.a[n]) --n;
       rez.a[0]=n;
       fix(rez.a);
       rez.semn=x.semn*y.semn;
       return rez;
}

BigInt operator%(const BigInt &x, const BigInt &y)
{
       BigInt cat=x/y;
       cat=x-(y*cat); 
       return cat;
}

int operator==(const BigInt &x, const BigInt &y)
{
    if (x.semn!=y.semn) return 0;
    for (unsigned i=0; i<=y.a[0]; i++)
        if (x.a[i]!=y.a[i]) return 0;
    return 1;
}

int operator!=(const BigInt &x, const BigInt &y)
{
    return !(x == y);
}

int operator<(const BigInt &y, const BigInt &x)
{
    if (y.semn < x.semn) return 1;
    if (y.semn > x.semn) return 0;
    if (y.a[0]<x.a[0]) return 1;
    if (y.a[0]>x.a[0]) return 0;
    unsigned k=y.a[0];
    while (x.a[k]==y.a[k] && k) k--;
    int ok=(y.a[k]<x.a[k]);
    if (x.semn) return ok; else return !ok;
}

int operator<=(const BigInt &y, const BigInt &x)
{
    return ((y<x) || (y==x));
}

int operator>(const BigInt &y, const BigInt &x)
{
    return !(y <= x);
}

int operator>=(const BigInt &y, const BigInt &x)
{
    return !(y < x);
}

void BigInt::write(FILE *f) const
{
     int i,n=a[0];
     if (semn==-1) fprintf(f, "-");
     fprintf(f, "%u", a[n]);
     for (i=n-1; i>0; i--)
         fprintf(f, "%.9u", a[i]);
     fprintf(f,"\n");
}

void BigInt::read(FILE *f)
{
     char c=0;
     semn=1;
     while (c<'0' || c>'9'){
           c=fgetc(f);
           if (c=='-') semn=-1;
     }
     string s="000000000"; 
     while (c>='0' && c<='9') s+=c, c=fgetc(f);
     int i, j, n=s.length()/9, lung=s.length()%9;
     a.resize(n+2);
     if (!lung) lung=9, n--;
     for (i=1; i<=n; i++)
         for (j=lung; j<lung+9; j++)
             a[i]=a[i]*10 + (s[(n-i)*9+j]-'0');        
     a[0]=n;
     while (!a[a[0]] && a[0]>0) a[0]--;
     fix(a);
     if (a[0]==1 && a[1]==0) semn=0;
}

BigInt pow(const BigInt &a, unsigned nr)
{
       BigInt rez=1;
       for (unsigned p=(1<<23); p>0; p/=2){
           rez=rez*rez;
           if (nr&p) rez=rez*a;
       }
       return rez;
}

BigInt fibo(unsigned n)
{
       BigInt a=1, b=1, f1, f3;
       unsigned p=1<<22, k=0;
       while (p>n) p/=2;
       p/=2; k=2;
       if (p && (n&p)) b=2, ++k;
       for (p/=2; p>1; p/=2){
           a=a*a;
           b=b*b;
           f3=4*b-a;
           if (k&1) f3.a[1]-=2; else f3.a[1]+=2;
           k*=2;
           if (n&p) k++;
           f1=a+b;
           if (n&p) b=f3, a=f3-f1;
           else b=f3-f1, a=f1;   
       }
       if (p){
          if (n&1){
             b = b+b;
             b = (b+a)*(b-a);
             if (k&1) b.a[1]-=2; else b.a[1]+=2;     
          }  else b=b*(b+a+a);
       }
       return b;
}

vector <unsigned> binar(BigInt a)
{
       vector <unsigned> rez;
       double p=ceil(log(base)/log((double)(1ll<<32))*a.a[0]);
       rez.resize((unsigned)p+1);
       unsigned nr=0;
       while (a.a[0]>1 || a.a[1]>0){
             unsigned rest=a%(1<<29);
             rez[nr/32]|=rest<<(nr%32);
             if (nr%32) rez[nr/32+1]|=rest>>(32-nr%32);
             a/=(1<<29);
             nr+=29;
       }
       while (rez.size() && rez[rez.size()-1]==0) rez.resize(rez.size()-1);
       return rez;
}

int miller(const BigInt &p, unsigned a)
{
    BigInt d=1, x=1, pm=p-1, eg;
    vector <unsigned> pow=binar(pm);
    unsigned mask=1u<<31;
    int nr=pow.size()-1;
    while (nr>=0 && (pow[nr] & mask)==0){
          mask/=2;
          if (!mask) mask=1u<<31, --nr; 
    }
    printf("Biti: %d\n", nr*32+(int) log2(mask));
    while (nr>=0){
          unsigned op=pow[nr] & mask;
          x=d;
          if (op) d=(d*d*a)%p; else d=(d*d)%p;
          if (op) eg=a; else eg=1;
          if (d==eg && x!=pm && x!=1) return 0;
          mask/=2;
          if (!mask) mask=1u<<31, --nr; 
    }
    return (d==1);
}

int IsPrime(const BigInt &p)
{
    unsigned i, primes[] = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79,
             83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173,
             179, 181, 191, 193, 197, 199, 211, 223, 227, 229};
    unsigned nr = sizeof(primes)/4;
    for (i=0; i<nr; i++){
        if (p < primes[i]*primes[i]) return 1;
        if (p%primes[i]==0) return 0;
    }
    for (i=0; i<3; i++) //depinde cat de sigur se vrea, asta e de ajuns in general
        if (!miller(p, primes[i])) return 0;
    return 1;   
}

BigInt gcd(BigInt a, BigInt b)
{
       BigInt rest;
       while (b!=0){
             rest=a%b;
             a=b;
             b=rest;
       }
       return a;
}

BigInt extended_gcd(BigInt a, BigInt b, BigInt &x, BigInt &y)
{
       x=1; y=0;
       BigInt cat, temp, x2=0, y2=1;
       while (b!=0){
             cat=a/b;
             temp=a%b;
             a=b; b=temp;
             
             temp=x2; 
             x2=x-(cat*x2);
             x=temp;
             
             temp=y2; 
             y2=y-(cat*y2);
             y=temp;
       }
       return a;
}

int main()
{
    freopen("numere2.in", "r", stdin);
    freopen("numere2.out", "w", stdout);



    int ord;
    BigInt n, SQR, P, i=99999, doi = 2, def;

    n.read(stdin);

    def = i;

    for(ord = 351;ord>0;--ord)
     {
      i = def;
      SQR = 0;
      while(i.a[0]>1 || i.a[1]>0)
       {
        do
         {
          SQR = SQR + i;
          P = pow(SQR,ord);
         } while(P < n);
        if(P > n)
         SQR = SQR - i;
        i=i/doi;
       }
      if(P == n)
       {
        SQR.write(stdout);
        printf("%d\n",ord);
        return 0;
       }
     }

    n.write(stdout);
    printf("\n1\n");
     
    return 0;
}