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

#define hashSize  5000001L

struct sNode {
       unsigned char *stacks;       // this is H_i
       unsigned char *stackNumbers; // this is for remembering 
                                    // the permutation
       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];
            n->stackNumbers = 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 );
      assert( n->stackNumbers );
      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

     // sort stacks in descending order
     for (int i=1; i<P; ++i) {
         int j = i;
         while ( j>0 && n->stacks[j-1] < n->stacks[j] ) {
               unsigned char tmp    = n->stacks[j-1];
               n->stacks[j-1] = n->stacks[j];
               n->stacks[j]   = tmp;
               // remember the permutation of the stacks:
               tmp = n->stackNumbers[j-1];
               n->stackNumbers[j-1] = n->stackNumbers[j];
               n->stackNumbers[j]   = tmp;
               j--;
         }
     }

     // 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.
    
     // remember: n->stacks is sorted in descending order
     for ( int to = P-1; to >= 0; --to ) {
         // if the last stack we moved coins to has had the same height
         // as this one, we don't have to take this one into consideration:
         if ( to<P-1 && n->stacks[to] == n->stacks[to+1] ) continue;
         
         for ( int from = 0; from < to; ++from ) {
             // if the last stack we took coins from has had the same height
             // as this one, we don't have to take this one inot consideration:
             if ( from>0 && n->stacks[from-1] == n->stacks[from] ) continue;
         
             // 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->stackNumbers[i] = n->stackNumbers[i];
                }
                a->stacks[from] -=  a->stacks[to];
                a->stacks[to]   +=  a->stacks[to];
                a->distance    =   n->distance + 1;
                a->from        =   n->hash;
                a->fromStack    =   n->stackNumbers[from];
                a->toStack      =   n->stackNumbers[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]) );
         n->stackNumbers[i] = i;
     }
     fclose(in);
     solve( n );
}

