Cod sursa(job #163637)

Utilizator VmanDuta Vlad Vman Data 22 martie 2008 14:50:27
Problema Vanatoare Scor 15
Compilator cpp Status done
Runda preONI 2008, Runda Finala, Clasele 11-12 Marime 3.3 kb
using namespace std;
#include <stdio.h>
#include <vector>

#define Nmax 32
#define PMax 66000
#define ll long long
#define maxim 1000000000000000000LL

int N,Pmax,i;
int C[Nmax],V[Nmax];
ll a[PMax],n[PMax],T;
char best[PMax];
int pow[Nmax];
vector<int> list[PMax];
vector<int>::iterator it;

void citire()
{
 freopen("vanatoare.in","r",stdin);
 scanf("%d %lld",&N,&T);
 for (i=0;i<N;++i)
     scanf("%lld %lld",&C[i],&V[i]);                  
}

 
inline int mod(int a, int n) {
    return a >= 0 ?
        a % n :
        n - ((-a) % n);
}

ll cmmdc(ll a,ll b)
{
 ll r;
 while (b>0)
       {
        r=mod(a,b);
        a=b;
        b=r;
       }
 return a;
}

void euclid(ll a, ll b, ll *d, ll *x, ll *y)
{
    if (b == 0) {
        *d = a;
        *x = 1;
        *y = 0;
    } else {
        ll x0, y0;
        euclid(b, mod(a,b), d, &x0, &y0);
        *x = y0;
        *y = x0 - (a / b) * y0;
    }
}

inline ll modul(ll a) { return a>0?a:-a; }

void chineza(ll a1, ll n1, ll a2, ll n2, ll *as, ll *ns)
{
 ll d,c1,c2,h,l1,l2,b1,b2,m1;
 d=cmmdc(n1,n2);
 euclid(n1,n2,&d,&c1,&c2);
 l1=(a2-a1)/d;
 l2=(a1-a2)/d;
 if (modul(c1*l1)>T || modul(c2*l2)>T) { *as=*ns=0; return; }
 b1=c1*l1;
 b2=c2*l2;
 if (maxim/n2 < n1/d) { *as=*ns=0; return; }
 h=(n1/d)*n2;
 if ((maxim-a1)/n1<b1) { *as=*ns=0; return; }
 *as=n1*b1+a1;
 *ns=h;
 if (modul(*as)>T || n1*b1+a1 != n2*b2+a2) *as=*ns=0;
 d=mod(*as,h);
 if (d) *as=d;
}

void dinamica()
{
 int nr=1,i;
 //scoate puterile lui 2
 pow[0]=1;
 for (i=1;i<=N;++i)
     pow[i]=pow[i-1]<<1;
 //submultimi
 while (nr<Pmax)
       {
        for (i=0; !(nr & pow[i]); ++i);
        //daca exista un singur mistret
        if (pow[i]==nr)
           {
            a[nr]=C[i];
            n[nr]=V[i];
            best[nr]=1;
            list[nr].push_back(C[i]);
           }
          else
              {
               //daca pot extinde sistemu, il rezolv
               if (best[nr-pow[i]]==1) chineza(C[i], V[i], a[nr-pow[i]], n[nr-pow[i]], &a[nr], &n[nr]);
               //daca am reusit sa extind sistemul, pun solutia
               if (n[nr]>0) 
                  {
                   best[nr]=best[nr-pow[i]];
                   list[nr].push_back(a[nr]);
                  } 
                  //nu am reusit sa extind sistemul, combin 2 solutii
                  else
                      {
                       best[nr]=2*N;
                       for (i=1;i<nr;++i)
                          if ((i&nr)==i && best[i]+best[nr-i]<best[nr])
                             {
                              best[nr]=best[i]+best[nr-i];
                              list[nr].clear();
                              for (it=list[i].begin();it<list[i].end();++it)
                                  list[nr].push_back(*it);
                              for (it=list[nr-i].begin();it<list[nr-i].end();++it)
                                  list[nr].push_back(*it);    
                             }
                      }    
              } 
        ++nr;
       }
}

int main()
{
 citire();
 Pmax=(1<<N);
 dinamica();
 freopen("vanatoare.out","w",stdout);
 printf("%d\n",best[Pmax-1]);
 for (it=list[Pmax-1].begin();it<list[Pmax-1].end();++it)
     printf("%d ",*it);
 fclose(stdout);    
 return 0;
}