#include <stdio.h>
#include <assert.h>
#include <stdlib.h>

#define hashSize  5000001L

struct sNode {
       unsigned char *stacks;       // this is H_i
       int distance; 
       sNode *next;
       int hash;               // hashcode of stacks
       int from;               // from which entry in hash[] did we come?
       int fromStack, toStack; // what was the last move
};

sNode* hash[hashSize];

sNode *first = NULL;
sNode *last  = NULL;

int P;
int targetHeight;

// this is just for measuring the hash-efficency
int inserted = 0, collisions = 0;

inline int equal( sNode * a, sNode * b ) {
    for ( int i=0; i<P; ++i ) {
        if ( a->stacks[i] != b->stacks[i] ) return 0;
    }
    return 1;
}

void printSolution( FILE *out, sNode *n ) {
     if ( n == NULL ) return;
     printSolution( out, hash[n->from] );
     if ( n->fromStack != -1 && n->toStack != -1 )
        fprintf(out, "%d %d\n", n->fromStack+1, n->toStack+1);
}

// this is for allocation of nodes:
// if we allocate memory for a node and don't store it in the hash because 
// the node is a dupe (occured in our BFS before), we don't deallocate the 
// memory, but use it the next time, a node is requested.
// For that readon we need the nextFree pointer.
sNode *nextFree = NULL;

inline sNode * newNode() {
      sNode * n;
      if ( nextFree == NULL ) {
            n               = new sNode;
            n->stacks       = new unsigned char[P];
            nextFree = n;
      } else n = nextFree;
      n->distance  = 0;
      n->next      = NULL;
      n->from      = -1;
      n->hash      = 0;
      n->fromStack = -1;
      n->toStack   = -1;

      assert( n->stacks );
      return n;
}

int insertNode( sNode * n ) {
     // we insert a new node into our hashtable only if it is not a dupe.
     // the function returns 1 if node inserted, or 0 otherwise

     // compute hashkey (11 and 87 are just some random numbers,
     // I didn't try to finde numbers that work better)
     unsigned long hk = n->stacks[0]*11;
     for ( int i=1; i<P; ++i ) {
         hk = hk * 87 + n->stacks[i];
     }

     // if hash[position] is occupied by *the same* node, we leave this
     // procedure. If hash[position] is occupied by another node, we try
     // hash[position++]. (linear probing)
     while ( hash[ hk%hashSize ] != NULL ) {
           if ( equal( hash[ hk%hashSize ], n ) ) return 0;
           ++hk;
           ++collisions;
     }

     hash[ hk%hashSize ] = n; // store node
     n->hash = hk%hashSize;   // and assign hash-Key
     
     // update our list. (remember: we do a breadth first search)
     if ( first == NULL ) first = n;
     if ( last  != NULL ) last->next = n;     
     last = n;

     nextFree = NULL; // we used this node and may not reuse it.
     ++inserted;
     //if ( (inserted & 1023) == 0 ) printf("%d/%d\n",inserted,collisions);

     // test whether we found the solution
     int solved = 1;
     for ( int i=0; i<P; ++i ) {
         if ( n->stacks[i] != targetHeight ) { solved = 0; break; }
     }

     // print it in that case
     if ( solved ) {
        FILE *out = fopen("stacks.out","w");
        //printf("%d\n",inserted);
        fprintf(out,"%d\n",n->distance);
        printSolution( out, n );
        fclose(out);
        exit(0);
     }
     return 1;
}

void createChildren( sNode * n ) {
     // this is to create nodes for all positions that we can reach by one
     // legal move from node n.
    
     // now n->stacks is not sorted!
     for ( int to = P-1; to >= 0; --to ) {
         for ( int from = 0; from < P; ++from ) {
         
             // we may only move coins from `from` to `to` if from contains
             // more coins than `to`. (not if both contain the same amount
             // of coins!)
             if ( n->stacks[ from ] > n->stacks[ to ] ) {
                // create the new node and insert it
                sNode *a = newNode();
                for ( int i=0; i<P; ++i ) {
                    a->stacks[i] = n->stacks[i];
                }
                a->stacks[from] -=  a->stacks[to];
                a->stacks[to]   +=  a->stacks[to];
                a->distance    =   n->distance + 1;
                a->from        =   n->hash;
                a->fromStack    =   from;
                a->toStack      =   to;

                insertNode(a);
             }
         }
     }
}

void solve( sNode *startNode ) {
     // count the coins and determine the height that the flattened stacks
     // will have.
     int coins = 0;
     for ( int i=0; i<P; ++i ) coins += startNode->stacks[i];
     targetHeight = coins/P;

     // do the breadth first search
     insertNode( startNode );
     while ( first != NULL ) {
           createChildren( first );
           first = first->next;
     }
     printf("Error: Not solvable\n");
}

void main(void) {
     FILE *in = fopen("stacks.in","r");
     fscanf(in,"%d",&P);
     sNode * n = newNode();
     
     for ( int i=0; i<P; ++i ) {
         fscanf(in,"%d", &(n->stacks[i]) );
     }
     fclose(in);
     solve( n );
}

