#include <string>
#include <vector>
#include <algorithm>
#include <iostream>
#include <sstream>

using namespace std;

#define SZ(a) (int((a).size())) //a size unsigned int-et ad vissza, és emiatt sok warning-ot csinál (hacsak nem cast-olunk mindenhol)
#define ALL(c) (c).begin(),(c).end() //ez az algorithm header-ben lévő sort, copy, reverse, stb. függvények használatakor hasznos
#define FOR(i,n) for(int (i)=0;(i)<(int)(n);(i)++) //rövidítés 0-tól n-ig menő for ciklusra

int base, hossz; //a számrendszer alapszáma, és a leghosszabb szám hossza
string s[3]; //a beolvasott betű-számok

int kioszt['z'+1]; //ebben tartjuk számon, hogy az egyes betűkhöz milyen érték van hozzárendelve
vector<bool> kiosztva; //ebben tartjuk számon, hogy mely számjegyek vannak kiosztva valamilyen betűnek

int msz=0; //megoldásszám

//egy rövidítés arra, hogy az i. sor j. oszlopában a már meglévő behelyettesítéseket figyelembe véve milyen számjegy áll (-1, ha még nincs kiosztva érték az ott álló betűhöz)
#define beh(i,j) (kioszt[s[i][j]])

inline char szj(int x){ //számjegy betűvé alakítása
	if(x<10)
		return '0'+x;
	else
		return 'A'-10+x;
}

vector<vector<int> > elof('z'+1); //ide fogjuk eltárolni minden számjegynek az összes előfordulását
vector<int> bvars; //ebben fogjuk tárolni minden oszlopra azt, hogy hány számjegy van benne rögzítve

void szamol(){ //ezt a rekurzió előtt hívjuk meg
	FOR(i,3)
		FOR(j,hossz){
			elof[s[i][j]].push_back(j);
			if(s[i][j]==' ')
				bvars[j]++; //a szóközhöz már hozzárendeltük a 0-t
		}
}

stringstream kiss; //ebben lesz a kiírandó megoldás
void megoldas(){
	msz++; //megoldásszám növelése

	static bool elso=true;
	if(!elso)
		return; //ha nem az első megoldást találtuk meg, akkor return;
	elso=false;

	for(int i='a';i<='z';i++)
		if(kioszt[i]>-1)
			kiss<<(char)i<<"="<<szj(kioszt[i])<<" "; //a kiírandó megoldás eltárolása
	kiss<<endl;
}

#define GYORS //ezzel lehet ki- és bekapcsolni azt a gyorsítást, hogy amikor lerögzítünk egy betűt, akkor ellenőrizzük, hogy nem alakult-e ki hiba valamelyik balra lévő oszlopban

void unbind(int i, int j, int x){ //ez vonja vissza az x számjegy rögzítését az i,j helyen lévő betűhöz
	beh(i,j)=-1;
	kiosztva[x]=false;
#ifdef GYORS
	vector<int> &ebet=elof[s[i][j]]; //ezzel hivatkozunk az aktuális pozíción lévő betű előfordulásait tároló tömbre
	FOR(k,SZ(ebet))
		bvars[ebet[k]]--;
#endif
}

void rec(int i, int j, int m);

void bind(int i, int j, int x, int ri, int rj, int rm){ //megróbálja hozzárendelni az i,j pozíción lévő betűhöz az x számjegyet, és a rekurzív hívást is ez végzi. A ri, rj, rm azt tárolják, hogy a rekurzív hívást milyen paraméterekkel kell végezni.
	if(!kiosztva[x]){ //ha még nem foglalt a számjegy
		beh(i,j)=x;
		kiosztva[x]=true;
#ifdef GYORS
		vector<int> &ebet=elof[s[i][j]]; //ezzel hivatkozunk az aktuális pozíción lévő betű előfordulásait tároló tömbre
		bool retfalse=false; //azt fogja jelezni, ha valahol hibát kapunk az elvégzett helyettesítéssel
		FOR(k,SZ(ebet)) //végigmegyünk minden olyan oszlopon, ahol előfordul a betű (ha egy oszlopban többször is előfordul, akkor többször van bent ebet-ben)
			if(++bvars[ebet[k]]==3) //növeljük az oszlopbeli rögzített betűk számát, és ha 3, akkor ellenőrzünk
				if((beh(0,ebet[k])+beh(1,ebet[k]))%base!=beh(2,ebet[k]) && ((beh(0,ebet[k])+beh(1,ebet[k]))+1)%base!=beh(2,ebet[k])) //ha nem stimmel az összeg (figyelembe véve, hogy az átvitel 0 vagy 1 lehet), akkor vágunk
					retfalse=true;
		if(retfalse){
			unbind(i,j,x); //ha hiba van valamelyik oszlopban, akkor vonjuk vissza a hozzárendelést
			return;
		}
#endif
		rec(ri,rj,rm); //a rekurzív hívás
		unbind(i,j,x); //a hozzárendelés visszavonása
		return;
	}else
		return; //akkor jutunk ide, ha már foglalt a számjegy
}

void rec(int i, int j, int m){ //az aktuális pozíció az i. sor, j. oszlop, és az átvitel m (ebben gyűlik össze az oszlopban lévő számjegyek összege)
	if(hossz<=j){ //ha az utolsó utáni oszlopban vagyunk		
		if(m==0) //ha nincs átvitel
			if(beh(2,hossz-1)!=0) //megnézzük, hogy nem 0-e az összeg első számjegye (mert az ellentmondana a feladat feltételeinek)
				megoldas(); //ez fogja növelni a megoldás-számlálót, és kiírni az első megoldást
	}else
		if(i!=2){ //ha nem az alsó sorban (azaz nem az összegben vagyunk)
			if(beh(i,j)!=-1) //ha már van hozzárendelve számjegy az aktuális pozíción lévő betűhöz
				rec(i+1,j,m+beh(i,j)); //rekurzív hívás (m-ben gyűlik az aktuális oszlop összege)
			else
				FOR(k,base) //végigmegyünk az összes számjegyen
					bind(i,j,k,i+1,j,m+k); //megpróbáljuk behelyettesíteni
		}else //i==2, vagyis az össze sorában vagyunk
			if(beh(i,j)==-1){ //ha még nincs rögzítve az itteni betű értéke
				int nm=m/base;
				m%=base;
				bind(i,j,m,0,j+1,nm);
			}else //ha már rögzítve van
				if(beh(i,j)==m%base) //megnézzük, hogy megfelel a rögzített érték az összegnek
					rec(0,j+1,m/base); //ha igen, akkor rekurzív hívás (az első sorra ugrunk, és a következő oszlopra, valamint átadjuk az átvitelt)
		
}

int main(){
	cin>>base>>s[0]>>s[1]>>s[2];

	//végzünk némi előfeldolgozást a három stringen
	hossz=max(max(SZ(s[0]),SZ(s[1])),SZ(s[2]));//eltároljuk a leghosszabb hosszát
	FOR(i,3){
		reverse(ALL(s[i]));//megfordítjuk, hogy könnyebb legyen az indexelés
		//kipótoljuk a két rövidebbet a leghosszabb hosszára, szóközök beszúrásával (ezzel megspórolunk néhány későbbi elágazást)
		int hiany=hossz-SZ(s[i]);//eltároljuk, hogy hány szóközt kell beszúrni
		FOR(j,hiany)
			s[i].push_back(' ');
	}
	bvars=vector<int>(hossz);
	szamol();

	//Inicializálások
	kiosztva=vector<bool>(base,false);
	for(int i='a';i<='z';i++)
		kioszt[i]=-1; //kezdetben egyik betű értéke sincs rögzítve
	kioszt[' ']=0; //a hosszok illesztésénél szúrtunk be szóközöket, tehát a szóköz 0-t jelent
	for(int i=0;i<base;i++)
		kiosztva[i]=false; //egyik számjegy sincs még kiosztva

	//A rekurzió elindítása
	rec(0,0,0);

	//Eredmény kiírása
	cout<<msz<<endl;
	cout<<kiss.str();

	//system("PAUSE");
	return 0;
}