//problem C - Rational Approx

 #include <iostream>
 
 using namespace std;

//define a fraction class 
 class frac
 {
   private:
     int num, denom;
   public:
     void assign(int,int);
     friend int Notone(frac&);
     friend int Notzero(frac&);
     friend frac operator / (frac&, frac&);
     friend frac operator * (frac&, frac&);
     friend frac operator + (frac&, frac&);
     friend frac operator - (frac&, frac&);
     friend ostream& operator << (ostream&, frac&);
 };
 int gcd(int n, int m)
 {
    if(m==0)
      return n;
    else
      return gcd(m,n%m);
 }

 void frac::assign(int n,int m)
 {  int g;
    g=gcd(n,m);
   num=n/g; denom=m/g;
 }

 //friend definitions
 int Notone(frac& f)
 {
   if(f.num==1 && f.denom==1)
     return 0;
   else
     return 1;
 }
 int Notzero(frac& f)
 {
   if(f.num==0)
     return 0;
   else
     return 1;
 }
 ostream& operator<<(ostream& os, frac& f)
 {
	if(f.denom<0)
	{ f.num *=-1;
	  f.denom *= -1;
	}
   if(f.denom==1)
     os<<f.num;
   else
     os<<f.num<<'/'<<f.denom;
   return os;
 }

 frac operator * (frac& f, frac& g)
 {
   frac t;
   int gg;
   t.num=f.num*g.num;
   t.denom=f.denom*g.denom;
   gg=gcd(t.num,t.denom);
   t.num /= gg;
   t.denom /= gg;
   return t;
 }
 frac operator / (frac& f, frac& g)
 {
   frac t;
   int gg;
   t.num=f.num*g.denom;
   t.denom=f.denom*g.num;
   gg=gcd(t.num,t.denom);
   if(gg!=0)
   {  t.num /= gg;
      t.denom /= gg;
   }
   return t;
 }
 frac operator + (frac& f, frac& g)
 {
   frac t;
   int gg;
   t.num=f.num*g.denom + g.num*f.denom;
   t.denom=f.denom*g.denom;
   gg=gcd(t.num,t.denom);
   t.num /= gg;
   t.denom /= gg;
   return t;
 }
 frac operator - (frac& f, frac& g)
 {
   frac t;
   int gg;
   t.num=f.num*g.denom - g.num*f.denom;
   t.denom=f.denom*g.denom;
   gg=gcd(t.num,t.denom);
   t.num /= gg;
   t.denom /= gg;
   return t;
 }

 frac M[12][12]; int f[16];

 void BuildM(int m,int n)
 {  int i,j;
    //zero out M
    for(i=0;i<10;i++)
    for(j=0;j<11;j++)
      M[i][j].assign(0,1);
    for(i=0;i<n;i++)
    for(j=0;j<m+n-i;j++)
      M[j][i].assign(f[m+n-1-(i+j)],1);
    //p(i)
    for(i=n;i<m+n+1;i++)
      M[i][i].assign(-1,1);

    M[0][m+n].assign(1,1);
}
void pivot(int i, int m, int n)  //pivot in col i
{
  int j,k;
  frac key, temp;
  //find pivot
  if(!Notzero(M[i][i]))
  {
    j=i+1;
    while(!Notzero(M[i][j]))
      j++;
    //exhcnage rows j and i
    for(k=0;k<n+m+2;k++)
    {
      temp = M[i][k];
      M[i][k] = M[j][k];
      M[j][k] = temp;
    }
  }
  //make pivot i =1
  if(Notone(M[i][i]))
  {
    key = M[i][i];
    for(k=0;k<m+n+1;k++)
      M[i][k] = M[i][k]/key;
  }
  //clear column i
  for(j=0;j<m+n;j++)
	if(j!=i && Notzero(M[j][i]))
    {
		key=M[j][i];
		for(k=0;k<n+m+1;k++) {
		  frac temp = key*M[i][k];
			M[j][k] = M[j][k] - temp;
		}
	}
}


void output(int m, int n)
{
	int i, degree;
	int zero=1;

	//print p
	for(i=m+n-1;i>=n;i--)
	  if (Notzero(M[i][n+m]))
	  {
		  if(!zero)
			  cout<<' ';
		  cout<<'('<<M[i][n+m]<<','<<m+n-1-i<<')';
		  zero=0;
	  }
	  if(zero)
		  cout<<"(0,0)";
	  cout<<endl;

	  //print q
      zero=1; degree=0;
	  for(i=0;i<n;i++)
	  {
	  if (Notzero(M[i][n+m]))
	  {
		  if(!zero)
			  cout<<' ';
		  cout<<'('<<M[i][n+m]<<','<<degree<<')';
		  zero=0;
	  }
	  degree++;
	  }
	  if(zero)
		  cout<<"(0,0)";
	  cout<<endl;
}

 int main()
 {   int i,m,n,count=1;

	cin>>m>>n;
	while(m>0 ||n>0)
	{
       for(i=0;i<m+n;i++)
		   cin>>f[i];
	   BuildM(m,n);		//builds the matrix to do Gaussian elimination on

	   //do Gaussian elimination on M
	   for(i=0;i<m+n;i++)
	   {
		   pivot(i,m,n);

	   }
       if(count>1) cout<<endl;	//print control

	   count++;
	   output(m,n);
	   cin>>m>>n;
	}
	return 0;
 }


