Problem:
Problem J:
C(O|W|A*RD*|S)* CROSSWORD
Puzzle
The first crossword puzzle was published on December 21, 1913 by Arthur Wynne. To celebrate the centennial of his great-great-grandfather's invention, John "Coward" Wynne
1
was struggling to make crossword puzzles. He was such a coward that whenever he thought of a tricky clue for a word, he couldn’t stop worrying if people would blame him for choosing a bad clue that could never mean that word. At the end of the day, he cowardly chose boring clues, which made his puzzles less interesting.
One day, he came up with a brilliant idea: puzzles in which word meanings do not matter, and yet interesting. He told his idea to his colleagues, who admitted that the idea was intriguing. They even named his puzzles "Coward's Crossword Puzzles" after his nickname.
However, making a Coward's crossword puzzle was not easy. Even though he did not have to think about word meanings, it was not easy to check if a puzzle has one and only one set of answers. As the day of the centennial anniversary was approaching, John started worrying if he would not be able to make interesting ones in time. Let's help John by writing a program that solves Coward's crossword puzzles.
Each puzzle consists of
h
×
w
cells along with
h
across clues and
w
down clues. The clues are regular expressions written in a pattern language whose BNF syntax is given as in the table below.
clue       ::= "^" pattern "$"
pattern    ::= simple | pattern "|" simple
simple     ::= basic | simple basic
basic      ::= elementary | elementary "*"
elementary ::= "." | "A" | "B" | ... | "Z" | "(" pattern ")"
Table J.1. BNF syntax of the pattern language.
The clues (as denoted by p and q below) match words (as denoted by s below) according to the
following rules.
^
p
$
matches
s
if
p
matches
s
.
p
|
q
matches a string
s
if
p
and/or
q
matches
s
.
pq
matches a string
s
if there exist
s
1
and
s
2
such that
s
1
s
2
=
s
,
p
matches
s
1
, and
q
matches
s
2
.
p
*
matches a string
s
if
s
is empty, or there exist
s
1
and
s
2
such that
s
1
s
2
=
s
,
p
matches
s
1
, and
p
*
matches
s
2
.
Each of
A
,
B
, . . . ,
Z
matches the respective letter itself.
(
p
)
matches
s
if
p
matches
s
.
.
is the shorthand of
(A|B|C|D|E|F|G|H|I|J|K|L|M|N|O|P|Q|R|S|T|U|V|W|X|Y|Z)
.
Below is an example of a Coward’s crossword puzzle with the answers filled in the cells.
Java Specific:
Submitted Java programs may not use classes in the java.util.regex package.
C++ Specific:
Submitted C++ programs may not use the std::regex class.
Input
The input consists of multiple datasets, each of which represents a puzzle given in the following format.
h
w
p
1
p
2
...
p
h
q
1
q
2
...
q
2
Here,
h
and
w
represent the vertical and horizontal numbers of cells, respectively, where 2 ≤
h,w
≤ 4. The
p
i
and
q
j
are the across and down clues for the
i
-th row and
j
-th column, respectively. Any clue has no more than 512 characters.
The last dataset is followed by a line of two zeros. You may assume that there are no more 
...(truncated)

Submitted solutions:

code_snippet: #include <iostream>
#include <string>
#include <vector>
#include <cstring>
#include <algorithm>
#include <cctype>
#include <cassert>
#include <array>
#include <set>
using namespace std;

#define ALL(v) begin(v),end(v)

namespace{

struct flags{
	using gtype = unsigned short;
	vector<gtype> v;
	gtype gen;
	void init(int sz){
		v.assign(sz, 0);
		gen = 1;
	}
	bool marked(int i){ return v[i] == gen; }
	void mark(int i){ v[i] = gen; }
	void reset(){
		++gen;
		if(gen == 0){
			memset(&v[0], 0, v.size() * sizeof(gtype));
			gen = 1;
		}
	}
};

using node = array<vector<int>, 27>;

struct parser{
	vector<node> nodes;
	const char *p;
	flags fs;
	vector<int> res;
	vector<int> tmpv[8];
	vector<int> cands(string s, int len){
		reverse(ALL(s));
		p = s.c_str() + 1;
		nodes.reserve(1100);
		nodes.emplace_back();
		int start = pattern(0);
		assert(*p == '^');
		fs.init(nodes.size());
		vector<int> us = {start};
		dfs(us, 0, len);

		return res;
	}
	void dfs(vector<int> &us, int bits, int rem){
		if(us.empty()){ return; }
		addeps(us);
		if(rem == 0){
			for(int u : us){
				if(u == 0){
					res.push_back(bits);
					return;
				}
			}
			return;
		}
		vector<int> &vs = tmpv[rem];
		for(int i = 1; i <= 26; ++i){
			vs.clear();
			fs.reset();
			for(int u : us){
				for(int v : nodes[u][i]){
					if(!fs.marked(v)){
						fs.mark(v);
						vs.push_back(v);
					}
				}
			}
			dfs(vs, bits << 5 | i, rem - 1);
		}
	}
	void addeps(vector<int> &us){
		fs.reset();
		for(size_t i = 0; i < us.size(); ++i){
			for(int v : nodes[us[i]][0]){
				if(!fs.marked(v)){
					fs.mark(v);
					us.push_back(v);
				}
			}
		}
	}
	int pattern(int u){
		const char *sp = p;
		int v = simple(u);
		set<string> dup; // ad-hoc optimization
		dup.emplace(sp, p);
		while(*p == '|'){
			++p;
			sp = p;
			int w = simple(u);
			if(dup.emplace(sp, p).second){
				nodes[v][0].push_back(w);
			}
		}
		return v;
	}
	int simple(int u){
		while(1){
			int v = basic(u);
			if(v == -1){ break; }
			u = v;
		}
		return u;
	}
	int basic(int u){
		if(*p == '*'){
			++p;
			int v = nodes.size();
			nodes.emplace_back();
			nodes[v][0].push_back(u);
			int w = nodes.size();
			nodes.emplace_back();
			nodes[w][0].push_back(v);
			int x = elementary(v);
			assert(x != -1);
			nodes[v][0].push_back(x);
			return w;
		}
		return elementary(u);
	}
	int elementary(int u){
		if(*p == ')'){
			++p;
			int v = pattern(u);
			assert(*p == '(');
			++p;
			return v;
		}
		if(*p == '.' || isupper(*p)){
			int v = nodes.size();
			nodes.emplace_back();
			if(*p == '.'){
				for(int i = 1; i <= 26; ++i){
					nodes[v][i].push_back(u);
				}
			}
			else{
				nodes[v][*p - 'A' + 1].push_back(u);
			}
			++p;
			return v;
		}
		return -1;
	}
};

struct solver{
	using pvii = pair<vector<int>,int>;
	vector<pvii> rcs, ccs;
	vector<int> rows, cols;
	vector<int> ans;
	vector<int> tmp;
	
	bool check(const pvii &v, int b, int und){
		int q = *lower_bound(ALL(v.first), b);
		return q < b + (1 << (und * 5));
	}
	
	void dfs(unsigned y, unsigned x){
		if(x == cols.size()){
			x = 0;
			++y;
			if(y == rows.size()){
				if(ans.empty()){
					ans = rows;
					return;
				}
				throw 0;
			}
		}
		int tmpr = rows[y], tmpc = cols[x];
		for(int i = 1; i <= 26; ++i){
			int dx = cols.size() - x - 1;
			int dy = rows.size() - y - 1;
			rows[y] |= i << dx* 5;
			cols[x] |= i << dy * 5;
			if(check(rcs[y], rows[y], dx) && check(ccs[x], cols[x], dy)){
				dfs(y, x + 1);
			}
			rows[y] = tmpr;
			cols[x] = tmpc;
		}
	}
	
	template <class T>
	vector<int> seconds(const vector<T> &v){
		vector<int> w;
		for(const auto &x : v){ w.push_back(x.second); }
		return w;
	}
	
	void perm(vector<int> &v, const vector<int> &p){
		tmp.clear();
		tmp.reserve(v.size() + 1);
		int n = p.size();
		for(int r : v){
			int s = 0;
			for(int q : p){
				s = s << 5 | ((r >> (n - q - 1) * 5) & 31);
			}
			tmp.push_back(s);
		}
		sort(ALL(tmp));
		tmp.push_back(0xfffff);
		v.swap(tmp);
	}
	
	void solve(int h, int w){
		for(int i = 0; i < h; ++i){
			string s;
			cin >> s;
			rcs.emplace_back(parser().cands(s, w), i);
		}
		for(int i = 0; i < w; ++i){
			string s;
			cin >> s;
			ccs.emplace_back(parser().cands(s, h), i);
		}

		sort(ALL(rcs), [](const pvii &a, const pvii &b){ return a.first.size() < b.first.size(); });
		sort(ALL(ccs), [](const pvii &a, const pvii &b){ return a.first.size() < b.first.size(); });
		vector<int> pr = seconds(rcs), pc = seconds(ccs);

		try{
			bool inv = rcs[0].first.size() > ccs[0].first.size();
			for(auto &a : rcs){
				perm(a.first, pc);
			}
			for(auto &a : ccs){
				perm(a.first, pr);
			}
			rows.assign(h, 0);
			cols.assign(w, 0);
			if(inv){
				rows.swap(cols);
				pr.swap(pc);
				rcs.swap(ccs);
			}
			dfs(0, 0);
			
			if(ans.empty()){
				cout << "none\n";
			}
			else{
				vector<string> out(h, string(w, '_'));
				for(size_t i = 0; i < rcs.size(); ++i)
				for(size_t j = 0; j < ccs.size(); ++j){
					int y = pr[i];
					int x = pc[j];
					if(inv){ swap(y, x); }
					out[y][x] = 'A' - 1 + ((ans[i] >> (ccs.size() - j - 1) * 5) & 31);
				}
				for(const string &s : out){
					cout << s << '\n';
				}
			}
		}catch(int){
			cout << "ambiguous\n";
		}
	}
};

}

int main(){
	int h, w;
	for(int cnt = 1; cin >> h >> w && h; ++cnt){
		solver().solve(h, w);
//		cerr << cnt << endl;
	}
}
accuracy: 1
time_ms: 1800
memory_kb: 22644
final_rank: 1

code_snippet: // very kuso problem

#include <cassert>// c
#include <iostream>// io
#include <iomanip>
#include <fstream>
#include <sstream>
#include <vector>// container
#include <map>
#include <set>
#include <queue>
#include <bitset>
#include <stack>
#include <algorithm>// other
#include <complex>
#include <numeric>
#include <functional>
#include <random>
#include <regex>
using namespace std;
typedef long long ll;typedef unsigned long long ull;typedef long double ld;

#define ALL(c) c.begin(),c.end()
#define IN(l,v,r) (l<=v && v < r)
template<class T> void UNIQUE(T& v){
	sort(ALL(v));
	v.erase(unique(ALL(v)),v.end());
}

#define DUMP(x) cerr << #x <<" = " << (x)
#define LINE() cerr<< " (L" << __LINE__ << ")"

#define range(i,l,r) for(int i=(int)l;i<(int)(r);i++)
// struct range{
// 	struct Iter{
// 		int v,step;
// 		Iter& operator++(){v+=step;return *this;}
// 		bool operator!=(Iter& itr){return v<itr.v;}
// 		int& operator*(){return v;}
// 	};
// 	Iter i, n;
// 	range(int i, int n,int step):i({i,step}), n({n,step}){}
// 	range(int i, int n):range(i,n,1){}
// 	range(int n):range(0,n){}
// 	Iter& begin(){return i;}
// 	Iter& end(){return n;}
// };

//input
template<typename T1,typename T2> istream& operator >> (istream& is,pair<T1,T2>& p){return is>>p.first>>p.second;}
template<typename T1> istream& operator >> (istream& is,tuple<T1>& t){return is >> get<0>(t);}
template<typename T1,typename T2> istream& operator >> (istream& is,tuple<T1,T2>& t){return is >> get<0>(t) >> get<1>(t);}
template<typename T1,typename T2,typename T3> istream& operator >> (istream& is,tuple<T1,T2,T3>& t){return is >>get<0>(t)>>get<1>(t)>>get<2>(t);}
template<typename T1,typename T2,typename T3,typename T4> istream& operator >> (istream& is,tuple<T1,T2,T3,T4>& t){return is >> get<0>(t)>>get<1>(t)>>get<2>(t)>>get<3>(t);}
template<typename T> istream& operator >> (istream& is,vector<T>& as){range(i,0,as.size())is >>as[i];return is;}
//output
template<typename T> ostream& operator << (ostream& os, const set<T>& ss){for(auto a:ss){if(a!=ss.begin())os<<" "; os<<a;}return os;}
template<typename T1,typename T2> ostream& operator << (ostream& os, const pair<T1,T2>& p){return os<<p.first<<" "<<p.second;}
template<typename K,typename V> ostream& operator << (ostream& os, const map<K,V>& m){bool isF=true;for(auto& p:m){if(!isF)os<<endl;os<<p;isF=false;}return os;}
template<typename T1> ostream& operator << (ostream& os, const tuple<T1>& t){return os << get<0>(t);}
template<typename T1,typename T2> ostream& operator << (ostream& os, const tuple<T1,T2>& t){return os << get<0>(t)<<" "<<get<1>(t);}
template<typename T1,typename T2,typename T3> ostream& operator << (ostream& os, const tuple<T1,T2,T3>& t){return os << get<0>(t)<<" "<<get<1>(t)<<" "<<get<2>(t);}
template<typename T1,typename T2,typename T3,typename T4> ostream& operator << (ostream& os, const tuple<T1,T2,T3,T4>& t){return os << get<0>(t)<<" "<<get<1>(t)<<" "<<get<2>(t)<<" "<<get<3>(t);}
template<typename T> ostream& operator << (ostream& os, const vector<T>& as){range(i,0,as.size()){if(i!=0)os<<" "; os<<as[i];}return os;}
template<typename T> ostream& operator << (ostream& os, const vector<vector<T>>& as){range(i,0,as.size()){if(i!=0)os<<endl; os<<as[i];}return os;}

struct Edge{
	char c;int f,t;
};

class NFA{
public:
	static NFA ONE;
	int N;
	vector<Edge> es;
	vector<vector<int>> f_cache, t_cache;
	
	vector<vector<int>> reachable;
	vector<vector<vector<int>>> trans;

	int s,t;
	NFA(int N = 0):N(N),s(0),t(1){
		f_cache = t_cache = vector<vector<int>>(N);
	}
	void add_edge(char c,int f,int t){
		int eid = es.size();
		es.push_back({c,f,t});
		f_cache[f].push_back(eid);t_cache[t].push_back(eid);
	}
	static NFA *disjoint(NFA* a,NFA* b){
		// merge technique
		NFA *res = (a->es.size() < b->es.size()? b : a),*add = (a->es.size() < b->es.size()? a : b);
		res->f_cache.resize(res->N + add->N);res->t_cache.resize(res->N + add->N);
		int eid = res->es.size();
		for(Edge& e:add->es){
			e.f += res->N; e.t += res->N;
			res->es.push_back(e);
			res->f_cache[e.f].push_back(eid);res->t_cache[e.t].push_back(eid);eid++;
		}
		res->N += add->N;
		return res;
	}
	static NFA* Union(NFA* a,NFA* b){
		bool bl = a->es.size() < b->es.size();
		int as = (bl?b->N:0)+a->s,at = (bl?b->N:0)+a->t,bs = (!bl?a->N:0)+b->s,bt = (!bl?a->N:0)+b->t;
		int S = a->N+b->N,T = a->N+b->N+1;
		NFA* ab = disjoint(a,b),*ab1 = disjoint(ab,&ONE),*res = disjoint(ab1,&ONE);
		res->add_edge('-',S,as); res->add_edge('-',S,bs);res->add_edge('-',at,T); res->add_edge('-',bt,T);
		res->s = S; res->t = T;
		return res;
	}
	static NFA* Concat(NFA* a,NFA* b){
		bool bl = a->es.size() < b->es.size();
		int as = (bl?b->N:0)+a->s,at = (bl?b->N:0)+a->t,bs = (!bl?a->N:0)+b->s,bt = (!bl?a->N:0)+b->t;
		NFA* res = disjoint(a,b);
		res->add_edge('-',at,bs);
		res->s = as; res->t = bt;
		return res;
	}
	static NFA* Star(NFA* a){
		NFA* res = disjoint(a,&ONE);
		res->add_edge('-',res->N-1,a->s); res->add_edge('-',a->t,res->N-1);
		res->s = res->t = res->N-1;
		return res;
	}

	// step
	void create_reachable(){
		queue<pair<int,int>> que; que.push({t,0});

		reachable = vector<vector<int>>(N,vector<int>(4));
		reachable[t][0] = true;
		while(!que.empty()){
			int t,d;tie(t,d) = que.front();que.pop();
			//back
			for(int eid:t_cache[t]){
				Edge& e = es[eid];
				if(e.c=='-'){
					if(!reachable[e.f][d]){
						reachable[e.f][d] = true;
						que.push({e.f,d});
					}
				}else{
					if(d+1 <reachable[e.f].size() && !reachable[e.f][d+1]){
						reachable[e.f][d+1] = true;
						que.push({e.f,d+1});
					}
				}
			}
		}
	}

	void create_trans(){
		trans = vector<vector<vector<int>>>(N,vector<vector<int>>(27));
		// eps trans
		range(st,0,N){
			vector<bool> passed(N);
			passed[st] = true;
			queue<int> que;
			range(i,0,passed.size())if(passed[i])que.push(i);
			while(!que.empty()){
				int s = que.front();que.pop();
				for(int eid : f_cache[s])if(es[eid].c =='-' && !passed[es[eid].t]){
					passed[es[eid].t] = true;
					que.push(es[eid].t);
				}
			}
			range(i,0,N)if(passed[i]) trans[st][26].push_back(i);
		}
		range(st,0,N)range(c,'A','Z'+1){
			// eps trans
			vector<bool> passed(N);
			for(int s:trans[st][26])passed[s]=true;
			vector<bool> npassed(N);
			queue<int> que;
			range(i,0,passed.size())if(passed[i])que.push(i);
			while(!que.empty()){
				int s = que.front();que.pop();
				for(int eid : f_cache[s])if((es[eid].c == c || es[eid].c =='.') && !npassed[es[eid].t]){
					npassed[es[eid].t] = true;
					que.push(es[eid].t);
				}
			}
			// eps trans
			range(i,0,N)if(npassed[i])for(int s:trans[i][26]) npassed[s] = true;
			range(s,0,npassed.size())if(npassed[s]){
				bool alleps = true;
				for(int eid : f_cache[s])alleps &= es[eid].c=='-';
				// ???????????? ?? ????§???????????????´?????????????????? for ?????????
				if(alleps && t != s)continue; 
				trans[st][c-'A'].push_back(s);
			}
		}
	}
} NFA::ONE = NFA(1);

class REGtoNFA{
public:
	static NFA* pattern(string& s,int& i,int e){
		NFA* p = simple(s,i,e);
		while(i < e && s[i]=='|'){
			i++;// '|'
			NFA* q = simple(s,i,e);
			p = NFA::Union(p,q);
		}
		return p;
	}
	static NFA* simple(string& s,int& i,int e){
		NFA* p = basic(s,i,e);
		while(i < e && s[i]!='|'){
			NFA* q = basic(s,i,e);
			p = NFA::Concat(p,q);
		}
		return p;
	}
	static NFA* basic(string& s,int& i,int e){
		NFA* p = elementary(s,i,e);
		if(i < (int)s.size() && s[i]=='*'){
			i++;// *
			p = NFA::Star(p);
		}
		return p;
	}
	static NFA* elementary(string& s,int& i,int e){
		NFA* p;
		if(s[i]=='('){
			i++; // (
			int d=1;
			for(int j=i;j<e;j++){
				if(s[j]=='(') d++;
				if(s[j]==')') d--;
				if(d==0){
					e = j;break;
				}
			}
			p = pattern(s,i,e);
			i++; // )
		}else{
			p = new NFA(2);
			p->add_edge(s[i],p->s,p->t);
			i++;// c
		}
		return p;
	}
};


int rc = 0;
class Main{
	public:
	int h,w;
	vector<string> tmp,res;

	vector<NFA> NFAs;
	vector<vector<int>> stats;

	void dfs(int y,int x,int c){
		if(rc>1)return;
		if(y==h){
			rc+=c; 
			res = tmp;
			return;
		}
		// ????????????????????¶??????????????´????????????????????????????????¢?´¢
		vector<vector<vector<int>>> nstats(2,vector<vector<int>>(26));
		vector<int> nfai={y,h+x};
		range(ni,0,2)for(char nc = 'A';nc <= 'Z'; nc++){
			for(int s:stats[nfai[ni]])for(int t:NFAs[nfai[ni]].trans[s][nc-'A']) nstats[ni][nc-'A'].push_back(t);
			UNIQUE(nstats[ni][nc-'A']);
		}
		vector<int> gid(26);iota(ALL(gid),0);
		for(char c1='A'; c1 <= 'Z';c1++)for(char c2='A'; c2 < c1;c2++)if(gid[c2-'A']==c2-'A'){
			if(nstats[0][c1-'A'].size() == nstats[0][c2-'A'].size() && nstats[1][c1-'A'].size() == nstats[1][c2-'A'].size()){
				bool eq = true;
				range(ni,0,2){
					range(i,0,nstats[ni][c1-'A'].size()){
						eq &= nstats[ni][c1-'A'][i] == nstats[ni][c2-'A'][i];
						if(!eq)break;
					}
					if(!eq)break;
				}
				if(eq){
					gid[c1-'A'] = gid[c2-'A'];
					break;
				}
			}
		}
		vector<int> gc(26);
		range(i,0,26)gc[gid[i]]++;

		for(char c='A'; c <= 'Z';c++)if(gid[c-'A']==c-'A'){
			tmp[y][x] = c;
			bool tmpOK = true;
			// eda ??????????????? de ikerukana ?
			{
				bool ok = false;
				for(int s:nstats[0][c-'A'])ok |= NFAs[y].reachable[s][w-1-x];
				tmpOK &= ok;
			}
			{
				bool ok = false;
				for(int s:nstats[1][c-'A'])ok |= NFAs[h+x].reachable[s][h-1-y];
				tmpOK &= ok;
			}
			if(x == w-1){
				bool ok = false;
				for(int s:nstats[0][c-'A'])ok |= s == NFAs[y].t;
				tmpOK &= ok;
			}
			if(y == h-1){
				bool ok = false;
				for(int s:nstats[1][c-'A'])ok |= s == NFAs[h+x].t;
				tmpOK &= ok;
			}
			if(tmpOK){
				vector<int> tmpp = stats[y],tmpq = stats[h+x];
				stats[y] = nstats[0][c-'A']; stats[h+x] = nstats[1][c-'A'];
				if(x+1 < w) dfs(y,x+1,gc[c-'A']);
				else dfs(y+1,0,gc[c-'A']);
				stats[y] = tmpp; stats[h + x] = tmpq;
			}
		}
	}

	void run(){
		while(true){
			cin >> h >> w;
			if(h==0 && w==0)break;
			rc = 0;
			tmp = res = vector<string>(h,string(w,'-'));
			vector<string> ss(h+w);cin >> ss;
 			// h <= 4, w <= 4
			NFAs = vector<NFA>(h+w);
			range(i,0,h+w){
				string s = "";
				range(j,1,ss[i].size()-1) s+=ss[i][j];
				int cur = 0, e = s.size();
				NFAs[i] = *REGtoNFA::pattern(s,cur,e);
			}
			range(i,0,h+w){
				NFAs[i].create_reachable();
				NFAs[i].create_trans();
			}
			stats = vector<vector<int>>(h+w);
			range(i,0,h+w) stats[i].push_back(NFAs[i].s);

			dfs(0,0,1);
			if(rc > 1){
				cout << "ambiguous" <<endl; 
			}else if(rc == 0){
				cout << "none" <<endl;
			}else{
				range(i,0,h) cout << res[i] <<endl;
			}
		}
	}
};

int main(){
	cout <<fixed<<setprecision(20);
	cin.tie(0);
	ios::sync_with_stdio(false);
	Main().run();
	return 0;
}
accuracy: 1
time_ms: 5620
memory_kb: 41044
final_rank: 4

code_snippet: // very kuso problem

#include <cassert>// c
#include <iostream>// io
#include <iomanip>
#include <fstream>
#include <sstream>
#include <vector>// container
#include <map>
#include <set>
#include <queue>
#include <bitset>
#include <stack>
#include <algorithm>// other
#include <complex>
#include <numeric>
#include <functional>
#include <random>
#include <regex>
using namespace std;
typedef long long ll;typedef unsigned long long ull;typedef long double ld;

#define ALL(c) c.begin(),c.end()
#define IN(l,v,r) (l<=v && v < r)
template<class T> void UNIQUE(T& v){
	sort(ALL(v));
	v.erase(unique(ALL(v)),v.end());
}

#define DUMP(x) cerr << #x <<" = " << (x)
#define LINE() cerr<< " (L" << __LINE__ << ")"

#define range(i,l,r) for(int i=(int)l;i<(int)(r);i++)
// struct range{
// 	struct Iter{
// 		int v,step;
// 		Iter& operator++(){v+=step;return *this;}
// 		bool operator!=(Iter& itr){return v<itr.v;}
// 		int& operator*(){return v;}
// 	};
// 	Iter i, n;
// 	range(int i, int n,int step):i({i,step}), n({n,step}){}
// 	range(int i, int n):range(i,n,1){}
// 	range(int n):range(0,n){}
// 	Iter& begin(){return i;}
// 	Iter& end(){return n;}
// };

//input
template<typename T1,typename T2> istream& operator >> (istream& is,pair<T1,T2>& p){return is>>p.first>>p.second;}
template<typename T1> istream& operator >> (istream& is,tuple<T1>& t){return is >> get<0>(t);}
template<typename T1,typename T2> istream& operator >> (istream& is,tuple<T1,T2>& t){return is >> get<0>(t) >> get<1>(t);}
template<typename T1,typename T2,typename T3> istream& operator >> (istream& is,tuple<T1,T2,T3>& t){return is >>get<0>(t)>>get<1>(t)>>get<2>(t);}
template<typename T1,typename T2,typename T3,typename T4> istream& operator >> (istream& is,tuple<T1,T2,T3,T4>& t){return is >> get<0>(t)>>get<1>(t)>>get<2>(t)>>get<3>(t);}
template<typename T> istream& operator >> (istream& is,vector<T>& as){range(i,0,as.size())is >>as[i];return is;}
//output
template<typename T> ostream& operator << (ostream& os, const set<T>& ss){for(auto a:ss){if(a!=ss.begin())os<<" "; os<<a;}return os;}
template<typename T1,typename T2> ostream& operator << (ostream& os, const pair<T1,T2>& p){return os<<p.first<<" "<<p.second;}
template<typename K,typename V> ostream& operator << (ostream& os, const map<K,V>& m){bool isF=true;for(auto& p:m){if(!isF)os<<endl;os<<p;isF=false;}return os;}
template<typename T1> ostream& operator << (ostream& os, const tuple<T1>& t){return os << get<0>(t);}
template<typename T1,typename T2> ostream& operator << (ostream& os, const tuple<T1,T2>& t){return os << get<0>(t)<<" "<<get<1>(t);}
template<typename T1,typename T2,typename T3> ostream& operator << (ostream& os, const tuple<T1,T2,T3>& t){return os << get<0>(t)<<" "<<get<1>(t)<<" "<<get<2>(t);}
template<typename T1,typename T2,typename T3,typename T4> ostream& operator << (ostream& os, const tuple<T1,T2,T3,T4>& t){return os << get<0>(t)<<" "<<get<1>(t)<<" "<<get<2>(t)<<" "<<get<3>(t);}
template<typename T> ostream& operator << (ostream& os, const vector<T>& as){range(i,0,as.size()){if(i!=0)os<<" "; os<<as[i];}return os;}
template<typename T> ostream& operator << (ostream& os, const vector<vector<T>>& as){range(i,0,as.size()){if(i!=0)os<<endl; os<<as[i];}return os;}

struct Edge{
	char c;int f,t;
};

class NFA{
public:
	static NFA ONE;
	int N;
	vector<Edge> es;
	vector<vector<int>> f_cache, t_cache;

	int s,t;
	NFA(int N = 0):N(N),s(0),t(1){
		f_cache = t_cache = vector<vector<int>>(N);
	}
	void add_edge(char c,int f,int t){
		int eid = es.size();
		es.push_back({c,f,t});
		f_cache[f].push_back(eid);t_cache[t].push_back(eid);
	}
	static NFA disjoint(NFA& a,NFA& b){
		// merge technique
		NFA& res = (a.es.size() < b.es.size()? b : a), add = (a.es.size() < b.es.size()? a : b);
		
		res.f_cache.resize(res.N + add.N);res.t_cache.resize(res.N + add.N);
		int eid = res.es.size();
		for(Edge& e:add.es){
			e.f += res.N; e.t += res.N;
			res.es.push_back(e);
			res.f_cache[e.f].push_back(eid);res.t_cache[e.t].push_back(eid);eid++;
		}
		res.N += add.N;
		return res;
	}
	static NFA Union(NFA& a,NFA& b){
		bool bl = a.es.size() < b.es.size();
		int as = (bl?b.N:0)+a.s,at = (bl?b.N:0)+a.t,aN = a.N, bs = (!bl?a.N:0)+b.s,bt = (!bl?a.N:0)+b.t, bN = b.N;
		int S = aN+bN,T = aN+bN+1;
		NFA ab = disjoint(a,b),ab1 = disjoint(ab,ONE),res = disjoint(ab1,ONE);
		res.add_edge('-',S,as); res.add_edge('-',S,bs);res.add_edge('-',at,T); res.add_edge('-',bt,T);
		res.s = S; res.t = T;
		return res;
	}
	static NFA Concat(NFA& a,NFA& b){
		bool bl = a.es.size() < b.es.size();
		int as = (bl?b.N:0)+a.s,at = (bl?b.N:0)+a.t,aN = a.N, bs = (!bl?a.N:0)+b.s,bt = (!bl?a.N:0)+b.t, bN = b.N;
		NFA res = disjoint(a,b);
		res.add_edge('-',at,bs);
		res.s = as; res.t = bt;
		return res;
	}
	static NFA Star(NFA& a){
		NFA res = disjoint(a,ONE);
		res.add_edge('-',res.N-1,a.s);
		res.add_edge('-',a.t,res.N-1);
		res.s = res.t = res.N-1;
		return res;
	}

	// parsing 
	static NFA pattern(string& s,int& i,int e){
		NFA p = simple(s,i,e);
		while(i < e && s[i]=='|'){
			i++;// '|'
			NFA q = simple(s,i,e);
			p = NFA::Union(p,q);
		}
		return p;
	}
	static NFA simple(string& s,int& i,int e){
		NFA p = basic(s,i,e);
		while(i < e && s[i]!='|'){
			NFA q = basic(s,i,e);
			p = NFA::Concat(p,q);
		}
		return p;
	}
	static NFA basic(string& s,int& i,int e){
		NFA p = elementary(s,i,e);
		if(i < (int)s.size() && s[i]=='*'){
			i++;// *
			p = NFA::Star(p);
		}
		return p;
	}
	static NFA elementary(string& s,int& i,int e){
		NFA p;
		if(s[i]=='('){
			i++; // (
			int d=1;
			for(int j=i;j<e;j++){
				if(s[j]=='(') d++;
				if(s[j]==')') d--;
				if(d==0){
					e = j;break;
				}
			}
			p = pattern(s,i,e);
			i++; // )
		}else{
			p = NFA(2);
			p.add_edge(s[i],p.s,p.t);
			i++;// c
		}
		return p;
	}
} NFA::ONE = NFA(1);

int rc = 0;
class Main{
	public:

	int h,w;
	vector<string> tmp,res;

	vector<NFA> NFAs;
	vector<vector<int>> stats;
	vector<vector<vector<int>>> reachable;
	vector<vector<vector<vector<int>>>> trans;

	void create_reachable(int nind){
		NFA& nfa = NFAs[nind];
		queue<pair<int,int>> que; que.push({nfa.t,0});
		reachable[nind][nfa.t][0] = true;
		while(!que.empty()){
			int t,d;tie(t,d) = que.front();que.pop();
			//back
			for(int eid:nfa.t_cache[t]){
				Edge& e = nfa.es[eid];
				if(e.c=='-'){
					if(!reachable[nind][e.f][d]){
						reachable[nind][e.f][d] = true;
						que.push({e.f,d});
					}
				}else{
					if(d+1 <reachable[nind][e.f].size() && !reachable[nind][e.f][d+1]){
						reachable[nind][e.f][d+1] = true;
						que.push({e.f,d+1});
					}
				}
			}
		}
	}

	void create_trans(int nind,int st,char nc){
		NFA& nfa = NFAs[nind];

		vector<bool> passed(nfa.N);
		passed[st] = true;
		// eps trans
		{
			queue<int> que;
			range(i,0,passed.size())if(passed[i])que.push(i);
			while(!que.empty()){
				int s = que.front();que.pop();
				for(int eid : nfa.f_cache[s])if(nfa.es[eid].c =='-' && !passed[nfa.es[eid].t]){
					passed[nfa.es[eid].t] = true;
					que.push(nfa.es[eid].t);
				}
			}
		}
		// trans
		{
			vector<bool> npassed(nfa.N);
			range(s,0,nfa.N)if(passed[s]) for(int eid : nfa.f_cache[s]){
				char c = nfa.es[eid].c;
				int t = nfa.es[eid].t;
				if(nc==c || c=='.') npassed[t] = true;
			}
			passed = npassed;
		}

		// eps trans
		{
			queue<int> que;
			range(i,0,passed.size())if(passed[i])que.push(i);
			while(!que.empty()){
				int s = que.front();que.pop();
				for(int eid : nfa.f_cache[s])if(nfa.es[eid].c =='-' && !passed[nfa.es[eid].t]){
					passed[nfa.es[eid].t] = true;
					que.push(nfa.es[eid].t);
				}
			}
		}

		range(s,0,passed.size())if(passed[s]){
			bool exeps = false, alleps = true;
			for(int eid : nfa.f_cache[s]){
				exeps |= nfa.es[eid].c=='-';
				alleps &= nfa.es[eid].c=='-';
			}
			// ?? ????§???????????????´?????????????????? for ?????????
			if(exeps && alleps && nfa.t != s)continue; 
			trans[nind][st][nc-'A'].push_back(s);
		}
	}

	void dfs(int y,int x,int c){
		// cerr << y <<" " << x <<endl;
		// cerr << tmp <<endl;

		if(rc>1)return;
		if(y==h){
			rc+=c;
			res = tmp;
			return;
		}

		// ????????????????????¶??????????????´????????????????????????????????¢?´¢
		vector<vector<int>> ynstats(26),xnstats(26);
		for(char nc = 'A';nc <= 'Z'; nc++){
			for(int s:stats[y])for(int t:trans[y][s][nc-'A'])ynstats[nc-'A'].push_back(t);
			UNIQUE(ynstats[nc-'A']);
		}
		for(char nc = 'A';nc <= 'Z'; nc++){
			for(int s:stats[h+x])for(int t:trans[h+x][s][nc-'A'])xnstats[nc-'A'].push_back(t);
			UNIQUE(xnstats[nc-'A']);
		}
		vector<int> gid(26);iota(ALL(gid),0);
		for(char c1='A'; c1 <= 'Z';c1++){
			for(char c2='A'; c2 < c1;c2++)if(gid[c2-'A']==c2-'A'){
				if(ynstats[c1-'A'].size() == ynstats[c2-'A'].size() && xnstats[c1-'A'].size() == xnstats[c2-'A'].size()){
					bool eq = true;
					range(i,0,ynstats[c1-'A'].size())eq &= ynstats[c1-'A'][i] == ynstats[c2-'A'][i];
					range(i,0,xnstats[c1-'A'].size())eq &= xnstats[c1-'A'][i] == xnstats[c2-'A'][i];
					if(eq){
						gid[c1-'A']=gid[c2-'A'];
						break;
					}
				}
			}
		}
		vector<int> gc(26);
		range(i,0,26)gc[gid[i]]++;

		for(char c='A'; c <= 'Z';c++)if(gid[c-'A']==c-'A'){
			tmp[y][x] = c;
			bool tmpOK = true;
			// eda ??????????????? de ikerukana ?
			{
				bool ok = false;
				for(int s:ynstats[c-'A'])ok |= reachable[y][s][w-1-x];
				tmpOK &= ok;
			}
			{
				bool ok = false;
				for(int s:xnstats[c-'A'])ok |= reachable[h+x][s][h-1-y];
				tmpOK &= ok;
			}
			if(x == w-1){
				bool ok = false;
				for(int s:ynstats[c-'A'])ok |= s == NFAs[y].t;
				tmpOK &= ok;
			}
			if(y == h-1){
				bool ok = false;
				for(int s:xnstats[c-'A'])ok |= s == NFAs[h+x].t;
				tmpOK &= ok;
			}
			if(tmpOK){
				vector<int> tmpp = stats[y],tmpq = stats[h+x];
				stats[y] = ynstats[c-'A']; stats[h+x] = xnstats[c-'A'];
				if(x+1 < w) dfs(y,x+1,gc[c-'A']);
				else dfs(y+1,0,gc[c-'A']);
				stats[y] = tmpp; stats[h + x] = tmpq;
			}
		}
	}

	void run(){
		while(true){
			cin >> h >> w;
			if(h==0 && w==0)break;
			rc = 0;
			tmp = res = vector<string>(h,string(w,'-'));
			vector<string> ss(h+w);cin >> ss;
 			// h <= 4, w <= 4
			NFAs = vector<NFA>(h+w);
			range(i,0,h+w){
				string s = "";
				range(j,1,ss[i].size()-1)s+=ss[i][j];
				int cur = 0, e = s.size();
				NFAs[i]= NFA::pattern(s,cur,e);
			}
			stats = vector<vector<int>>(h+w);
			range(i,0,h+w) stats[i].push_back(NFAs[i].s);

			reachable = vector<vector<vector<int>>>(h+w);
			range(i,0,h){
				reachable[i] = vector<vector<int>>(NFAs[i].N);
				range(s,0,NFAs[i].N) reachable[i][s] = vector<int>(h+1);
			}
			range(i,0,w){
				reachable[h+i] = vector<vector<int>>(NFAs[h+i].N);
				range(s,0,NFAs[h+i].N) reachable[h+i][s] = vector<int>(w+1);
			}
			range(i,0,h+w) create_reachable(i);
			
			trans = vector<vector<vector<vector<int>>>>(h+w);
			range(i,0,h+w){
				trans[i] = vector<vector<vector<int>>>(NFAs[i].N,vector<vector<int>>(26));
				range(s,0,NFAs[i].N)range(c,'A','Z'+1)create_trans(i,s,c);
			}

			// cerr << NFAs[0].t <<endl;
			// range(i,0,NFAs[0].es.size()){
			// 	cerr << NFAs[0].es[i].c <<" " <<NFAs[0].es[i].f <<" " <<NFAs[0].es[i].t <<endl;
			// }
			// cerr << NFAs[0].t_cache <<endl;

			dfs(0,0,1);
			if(rc > 1){
				cout << "ambiguous" <<endl; 
			}else if(rc == 0){
				cout << "none" <<endl;
			}else{
				range(i,0,h) cout << res[i] <<endl;
			}
		}
	}
};

int main(){
	cout <<fixed<<setprecision(20);
	cin.tie(0);
	ios::sync_with_stdio(false);
	Main().run();
	return 0;
}
accuracy: 1
time_ms: 5390
memory_kb: 29680
final_rank: 3

code_snippet: // very kuso problem

#include <cassert>// c
#include <iostream>// io
#include <iomanip>
#include <fstream>
#include <sstream>
#include <vector>// container
#include <map>
#include <set>
#include <queue>
#include <bitset>
#include <stack>
#include <algorithm>// other
#include <complex>
#include <numeric>
#include <functional>
#include <random>
#include <regex>
using namespace std;
typedef long long ll;typedef unsigned long long ull;typedef long double ld;

#define ALL(c) c.begin(),c.end()
#define IN(l,v,r) (l<=v && v < r)
template<class T> void UNIQUE(T& v){
	sort(ALL(v));
	v.erase(unique(ALL(v)),v.end());
}

#define DUMP(x) cerr << #x <<" = " << (x)
#define LINE() cerr<< " (L" << __LINE__ << ")"

#define range(i,l,r) for(int i=(int)l;i<(int)(r);i++)
// struct range{
// 	struct Iter{
// 		int v,step;
// 		Iter& operator++(){v+=step;return *this;}
// 		bool operator!=(Iter& itr){return v<itr.v;}
// 		int& operator*(){return v;}
// 	};
// 	Iter i, n;
// 	range(int i, int n,int step):i({i,step}), n({n,step}){}
// 	range(int i, int n):range(i,n,1){}
// 	range(int n):range(0,n){}
// 	Iter& begin(){return i;}
// 	Iter& end(){return n;}
// };

//input
template<typename T1,typename T2> istream& operator >> (istream& is,pair<T1,T2>& p){return is>>p.first>>p.second;}
template<typename T1> istream& operator >> (istream& is,tuple<T1>& t){return is >> get<0>(t);}
template<typename T1,typename T2> istream& operator >> (istream& is,tuple<T1,T2>& t){return is >> get<0>(t) >> get<1>(t);}
template<typename T1,typename T2,typename T3> istream& operator >> (istream& is,tuple<T1,T2,T3>& t){return is >>get<0>(t)>>get<1>(t)>>get<2>(t);}
template<typename T1,typename T2,typename T3,typename T4> istream& operator >> (istream& is,tuple<T1,T2,T3,T4>& t){return is >> get<0>(t)>>get<1>(t)>>get<2>(t)>>get<3>(t);}
template<typename T> istream& operator >> (istream& is,vector<T>& as){range(i,0,as.size())is >>as[i];return is;}
//output
template<typename T> ostream& operator << (ostream& os, const set<T>& ss){for(auto a:ss){if(a!=ss.begin())os<<" "; os<<a;}return os;}
template<typename T1,typename T2> ostream& operator << (ostream& os, const pair<T1,T2>& p){return os<<p.first<<" "<<p.second;}
template<typename K,typename V> ostream& operator << (ostream& os, const map<K,V>& m){bool isF=true;for(auto& p:m){if(!isF)os<<endl;os<<p;isF=false;}return os;}
template<typename T1> ostream& operator << (ostream& os, const tuple<T1>& t){return os << get<0>(t);}
template<typename T1,typename T2> ostream& operator << (ostream& os, const tuple<T1,T2>& t){return os << get<0>(t)<<" "<<get<1>(t);}
template<typename T1,typename T2,typename T3> ostream& operator << (ostream& os, const tuple<T1,T2,T3>& t){return os << get<0>(t)<<" "<<get<1>(t)<<" "<<get<2>(t);}
template<typename T1,typename T2,typename T3,typename T4> ostream& operator << (ostream& os, const tuple<T1,T2,T3,T4>& t){return os << get<0>(t)<<" "<<get<1>(t)<<" "<<get<2>(t)<<" "<<get<3>(t);}
template<typename T> ostream& operator << (ostream& os, const vector<T>& as){range(i,0,as.size()){if(i!=0)os<<" "; os<<as[i];}return os;}
template<typename T> ostream& operator << (ostream& os, const vector<vector<T>>& as){range(i,0,as.size()){if(i!=0)os<<endl; os<<as[i];}return os;}

struct Edge{
	char c;int f,t;
};

class NFA{
public:
	// (source)initial state = 0, (target)acc state = 0 or 1
	int N;
	vector<Edge> es;
	vector<vector<int>> f_cache, t_cache;

	int s,t;
	NFA(int N = 0):N(N),s(0),t(1){
		f_cache = t_cache = vector<vector<int>>(N);
	}
	void add_edge(char c,int f,int t){
		int eid = es.size();
		es.push_back({c,f,t});
		f_cache[f].push_back(eid);t_cache[t].push_back(eid);
	}
	void disjoint(NFA& b){
		f_cache.resize(N+b.N);
		t_cache.resize(N+b.N);
		for(Edge& e:b.es){
			e.f+=N; e.t+=N;
			int eid = es.size();
			es.push_back(e);
			f_cache[e.f].push_back(eid); t_cache[e.t].push_back(eid);
		}
		N +=b.N;
	}
	void Union(NFA b){
		int as = s,at = t,aN = N, bs = b.s,bt = b.t, bN = b.N;
		disjoint(b);
		NFA sp = NFA(1);
		disjoint(sp);
		NFA tp = NFA(1);
		disjoint(tp);
		add_edge('-',aN+bN,as);
		add_edge('-',aN+bN,aN + bs);
		add_edge('-',at,aN+bN+1);
		add_edge('-',aN+bt,aN+bN+1);
		s = aN+bN; t = aN + bN +1;
	}
	void Concat(NFA b){
		int as = s,at = t,aN = N, bs = b.s,bt = b.t, bN = b.N;
		disjoint(b);
		add_edge('-',at,aN + bs);
		s = as;t = aN + bt;
	}
	void Star(){
		NFA sp = NFA(1);
		disjoint(sp);
		add_edge('-',N-1,s);
		add_edge('-',t,N-1);
		s = t = N-1;
	}

	// parsing 
	static NFA pattern(string& s,int& i,int e){
		NFA p = simple(s,i,e);
		while(i < e && s[i]=='|'){
			i++;// '|'
			p.Union(simple(s,i,e));
		}
		return p;
	}
	static NFA simple(string& s,int& i,int e){
		NFA p = basic(s,i,e);
		while(i < e && s[i]!='|'){
			p.Concat(basic(s,i,e));
		}
		return p;
	}
	static NFA basic(string& s,int& i,int e){
		NFA p = elementary(s,i,e);
		if(i < (int)s.size() && s[i]=='*'){
			i++;// *
			p.Star();
		}
		return p;
	}
	static NFA elementary(string& s,int& i,int e){
		NFA p;
		if(s[i]=='('){
			i++; // (
			int d=1;
			for(int j=i;j<e;j++){
				if(s[j]=='(') d++;
				if(s[j]==')') d--;
				if(d==0){
					e = j;break;
				}
			}
			p = pattern(s,i,e);
			i++; // )
		}else{
			p = NFA(2);
			p.add_edge(s[i],p.s,p.t);
			i++;// c
		}
		return p;
	}
};


int rc = 0;
class Main{
	public:

	int h,w;
	vector<string> tmp,res;

	vector<NFA> NFAs;
	vector<vector<int>> stats;
	vector<vector<vector<int>>> reachable;
	vector<vector<vector<vector<int>>>> trans;

	void create_reachable(int nind){
		NFA& nfa = NFAs[nind];
		queue<pair<int,int>> que; que.push({nfa.t,0});
		reachable[nind][nfa.t][0] = true;
		while(!que.empty()){
			int t,d;tie(t,d) = que.front();que.pop();
			//back
			for(int eid:nfa.t_cache[t]){
				Edge& e = nfa.es[eid];
				if(e.c=='-'){
					if(!reachable[nind][e.f][d]){
						reachable[nind][e.f][d] = true;
						que.push({e.f,d});
					}
				}else{
					if(d+1 <reachable[nind][e.f].size() && !reachable[nind][e.f][d+1]){
						reachable[nind][e.f][d+1] = true;
						que.push({e.f,d+1});
					}
				}
			}
		}
	}

	void create_trans(int nind,int st,char nc){
		NFA& nfa = NFAs[nind];

		vector<bool> passed(nfa.N);
		passed[st] = true;
		// eps trans
		{
			queue<int> que;
			range(i,0,passed.size())if(passed[i])que.push(i);
			while(!que.empty()){
				int s = que.front();que.pop();
				for(int eid : nfa.f_cache[s])if(nfa.es[eid].c =='-' && !passed[nfa.es[eid].t]){
					passed[nfa.es[eid].t] = true;
					que.push(nfa.es[eid].t);
				}
			}
		}
		// trans
		{
			vector<bool> npassed(nfa.N);
			range(s,0,nfa.N)if(passed[s]) for(int eid : nfa.f_cache[s]){
				char c = nfa.es[eid].c;
				int t = nfa.es[eid].t;
				if(nc==c || c=='.') npassed[t] = true;
			}
			passed = npassed;
		}

		// eps trans
		{
			queue<int> que;
			range(i,0,passed.size())if(passed[i])que.push(i);
			while(!que.empty()){
				int s = que.front();que.pop();
				for(int eid : nfa.f_cache[s])if(nfa.es[eid].c =='-' && !passed[nfa.es[eid].t]){
					passed[nfa.es[eid].t] = true;
					que.push(nfa.es[eid].t);
				}
			}
		}

		range(s,0,passed.size())if(passed[s]){
			bool exeps = false, alleps = true;
			for(int eid : nfa.f_cache[s]){
				exeps |= nfa.es[eid].c=='-';
				alleps &= nfa.es[eid].c=='-';
			}
			// ?? ????§???????????????´?????????????????? for ?????????
			if(exeps && alleps && nfa.t != s)continue; 
			trans[nind][st][nc-'A'].push_back(s);
		}
	}

	void dfs(int y,int x,int c){
		// cerr << y <<" " << x <<endl;
		// cerr << tmp <<endl;

		if(rc>1)return;
		if(y==h){
			rc+=c;
			res = tmp;
			return;
		}

		// ????????????????????¶??????????????´????????????????????????????????¢?´¢
		vector<vector<int>> ynstats(26),xnstats(26);
		for(char nc = 'A';nc <= 'Z'; nc++){
			for(int s:stats[y])for(int t:trans[y][s][nc-'A'])ynstats[nc-'A'].push_back(t);
			UNIQUE(ynstats[nc-'A']);
		}
		for(char nc = 'A';nc <= 'Z'; nc++){
			for(int s:stats[h+x])for(int t:trans[h+x][s][nc-'A'])xnstats[nc-'A'].push_back(t);
			UNIQUE(xnstats[nc-'A']);
		}
		vector<int> gid(26);iota(ALL(gid),0);
		for(char c1='A'; c1 <= 'Z';c1++){
			for(char c2='A'; c2 < c1;c2++)if(gid[c2-'A']==c2-'A'){
				if(ynstats[c1-'A'].size() == ynstats[c2-'A'].size() && xnstats[c1-'A'].size() == xnstats[c2-'A'].size()){
					bool eq = true;
					range(i,0,ynstats[c1-'A'].size())eq &= ynstats[c1-'A'][i] == ynstats[c2-'A'][i];
					range(i,0,xnstats[c1-'A'].size())eq &= xnstats[c1-'A'][i] == xnstats[c2-'A'][i];
					if(eq){
						gid[c1-'A']=gid[c2-'A'];
						break;
					}
				}
			}
		}
		vector<int> gc(26);
		range(i,0,26)gc[gid[i]]++;

		for(char c='A'; c <= 'Z';c++)if(gid[c-'A']==c-'A'){
			tmp[y][x] = c;
			bool tmpOK = true;
			// eda ??????????????? de ikerukana ?
			{
				bool ok = false;
				for(int s:ynstats[c-'A'])ok |= reachable[y][s][w-1-x];
				tmpOK &= ok;
			}
			{
				bool ok = false;
				for(int s:xnstats[c-'A'])ok |= reachable[h+x][s][h-1-y];
				tmpOK &= ok;
			}
			if(x == w-1){
				bool ok = false;
				for(int s:ynstats[c-'A'])ok |= s == NFAs[y].t;
				tmpOK &= ok;
			}
			if(y == h-1){
				bool ok = false;
				for(int s:xnstats[c-'A'])ok |= s == NFAs[h+x].t;
				tmpOK &= ok;
			}
			if(tmpOK){
				vector<int> tmpp = stats[y],tmpq = stats[h+x];
				stats[y] = ynstats[c-'A']; stats[h+x] = xnstats[c-'A'];
				if(x+1 < w) dfs(y,x+1,gc[c-'A']);
				else dfs(y+1,0,gc[c-'A']);
				stats[y] = tmpp; stats[h + x] = tmpq;
			}
		}
	}

	void run(){
		while(true){
			cin >> h >> w;
			if(h==0 && w==0)break;
			rc = 0;
			tmp = res = vector<string>(h,string(w,'-'));
			vector<string> ss(h+w);cin >> ss;
 			// h <= 4, w <= 4
			NFAs = vector<NFA>(h+w);
			range(i,0,h+w){
				string s = "";
				range(j,1,ss[i].size()-1)s+=ss[i][j];
				int cur = 0, e = s.size();
				NFAs[i]= NFA::pattern(s,cur,e);
			}
			stats = vector<vector<int>>(h+w);
			range(i,0,h+w) stats[i].push_back(NFAs[i].s);

			reachable = vector<vector<vector<int>>>(h+w);
			range(i,0,h){
				reachable[i] = vector<vector<int>>(NFAs[i].N);
				range(s,0,NFAs[i].N) reachable[i][s] = vector<int>(h+1);
			}
			range(i,0,w){
				reachable[h+i] = vector<vector<int>>(NFAs[h+i].N);
				range(s,0,NFAs[h+i].N) reachable[h+i][s] = vector<int>(w+1);
			}
			range(i,0,h+w) create_reachable(i);
			
			trans = vector<vector<vector<vector<int>>>>(h+w);
			range(i,0,h+w){
				trans[i] = vector<vector<vector<int>>>(NFAs[i].N,vector<vector<int>>(26));
				range(s,0,NFAs[i].N)range(c,'A','Z'+1)create_trans(i,s,c);
			}

			// cerr << NFAs[0].t <<endl;
			// range(i,0,NFAs[0].es.size()){
			// 	cerr << NFAs[0].es[i].c <<" " <<NFAs[0].es[i].f <<" " <<NFAs[0].es[i].t <<endl;
			// }
			// cerr << NFAs[0].t_cache <<endl;
			
			dfs(0,0,1);
			if(rc > 1){
				cout << "ambiguous" <<endl; 
			}else if(rc == 0){
				cout << "none" <<endl;
			}else{
				range(i,0,h) cout << res[i] <<endl;
			}
		}
	}
};

int main(){
	cout <<fixed<<setprecision(20);
	cin.tie(0);
	ios::sync_with_stdio(false);
	Main().run();
	return 0;
}
accuracy: 1
time_ms: 5100
memory_kb: 29868
final_rank: 2