Problem:
Reading Brackets in English
Shun and his professor are studying Lisp and S-expressions. Shun is in Tokyo in order to make a presen-
tation of their research. His professor cannot go with him because of another work today.
He was making final checks for his slides an hour ago. Then, unfortunately, he found some serious
mistakes! He called his professor immediately since he did not have enough data in his hand to fix the
mistakes.
Their discussion is still going on now. The discussion looks proceeding with difficulty. Most of their data
are written in S-expressions, so they have to exchange S-expressions via telephone.
Your task is to write a program that outputs S-expressions represented by a given English phrase.
Input
The first line of the input contains a single positive integer
N
, which represents the number of test cases.
Then
N
test cases follow.
Each case consists of a line. The line contains an English phrase that represents an S-expression. The
length of the phrase is up to 1000 characters.
The rules to translate an S-expression are as follows.
An S-expression which has one element is translated into “a list of <
the element of the S-expression
>”. (e.g. “(A)” will be “a list of A”)
An S-expression which has two elements is translated into “a list of <
the first element of the S-expression
> and <
the second element of the S-expression
>”. (e.g. “(A B)” will be “a list of A and B”)
An S-expression which has more than three elements is translated into “a list of <
the first element of the S-expression
>, <
the second element of the S-expression
>, . . . and <
the last element
   of the S-expression
>”. (e.g. “(A B C D)” will be “a list of A, B, C and D”)
The above rules are applied recursively. (e.g. “(A (P Q) B (X Y Z) C)” will be “a list of
   A, a list of P and Q, B, a list of X, Y and Z and C”)
Each atomic element of an S-expression is a string made of less than 10 capital letters. All words (“a”,
“list”, “of” and “and”) and atomic elements of S-expressions are separated by a single space character,
but no space character is inserted before comma (”,”). No phrases for empty S-expressions occur in the
input. You can assume that all test cases can be translated into S-expressions, but the possible expressions
may not be unique.
Output
For each test case, output the corresponding S-expression in a separate line. If the given phrase involves
two or more different S-expressions, output “AMBIGUOUS” (without quotes).
A single space character should be inserted between the elements of the S-expression, while no space
character should be inserted after open brackets (“(”) and before closing brackets (“)”).
Sample Input
4
a list of A, B, C and D
a list of A, a list of P and Q, B, a list of X, Y and Z and C
a list of A
a list of a list of A and B
Output for the Sample Input
(A B C D)
(A (P Q) B (X Y Z) C)
(A)
AMBIGUOUS

Submitted solutions:

code_snippet: // AOJ #2067 Reading Brackets in English
// 2025.3.20

#include <bits/stdc++.h>
using namespace std;

struct Ans {
    bool valid, amb;
    string s;
};

Ans mergeAns(const Ans &a, const Ans &b) {
    if(!a.valid) return b;
    if(!b.valid) return a;
    Ans ret;
    ret.valid = true;
    if(a.amb || b.amb || a.s != b.s) ret.amb = true;
    else {
        ret.amb = false;
        ret.s = a.s;
    }
    return ret;
}

typedef unordered_map<int, Ans> MapAns;

void unionMap(MapAns &dest, const MapAns &src) {
    for(auto &pr : src) {
        int pos = pr.first;
        if(dest.find(pos) == dest.end()) dest[pos] = pr.second;
        else dest[pos] = mergeAns(dest[pos], pr.second);
    }
}

vector<string> T;

unordered_map<int, MapAns> memoS, memoE, memoL, memoList;

MapAns parseS(int);
MapAns parseE(int);
MapAns parseL(int);
MapAns parseList(int);

MapAns parseS(int i) {
    if(memoS.count(i)) return memoS[i];
    MapAns res;
    if(i+3 <= (int)T.size() && T[i]=="a" && T[i+1]=="list" && T[i+2]=="of") {
        MapAns mL = parseL(i+3);
        for(auto &pr : mL) {
            int pos = pr.first;
            Ans an;
            an.valid = pr.second.valid;
            an.amb = pr.second.amb;
            an.s = "(" + pr.second.s + ")";
            res[pos] = an;
        }
    }
    memoS[i] = res;
    return res;
}

MapAns parseE(int i) {
    if(memoE.count(i)) return memoE[i];
    MapAns res;
    MapAns mS = parseS(i);
    unionMap(res, mS);
    if(i+1 <= (int)T.size()) {
        string tok = T[i];
        bool isAtom = true;
        for(char c : tok) {
            if(!isupper(c)) { isAtom = false; break; }
        }
        if(isAtom) {
            Ans an;
            an.valid = true;
            an.amb = false;
            an.s = tok;
            res[i+1] = an;
        }
    }
    memoE[i] = res;
    return res;
}

MapAns parseList(int i) {
    if(memoList.count(i)) return memoList[i];
    MapAns res;
    MapAns mE = parseE(i);
    for(auto &pr : mE) {
        int pos = pr.first;
        res[pos] = mergeAns(res[pos], pr.second);
        if(pos < (int)T.size() && T[pos] == ",") {
            MapAns mList = parseList(pos+1);
            for(auto &pr2 : mList) {
                int pos2 = pr2.first;
                Ans an;
                if(pr.second.valid && pr2.second.valid) {
                    an.valid = true;
                    string cand = pr.second.s + " " + pr2.second.s;
                    an.amb = pr.second.amb || pr2.second.amb;
                    an.s = cand;
                } else an.valid = false;
                res[pos2] = mergeAns(res[pos2], an);
            }
        }
    }
    memoList[i] = res;
    return res;
}

MapAns parseL(int i) {
    if(memoL.count(i)) return memoL[i];
    MapAns res;
    MapAns mE = parseE(i);
    unionMap(res, mE);
    MapAns mList = parseList(i);
    for(auto &pr : mList) {
        int pos = pr.first;
        if(pos < (int)T.size() && T[pos]=="and") {
            MapAns mE2 = parseE(pos+1);
            for(auto &pr2 : mE2) {
                int pos2 = pr2.first;
                Ans an;
                if(pr.second.valid && pr2.second.valid) {
                    an.valid = true;
                    string cand = pr.second.s + " " + pr2.second.s;
                    an.s = cand;
                    an.amb = pr.second.amb || pr2.second.amb;
                } else an.valid = false;
                res[pos2] = mergeAns(res[pos2], an);
            }
        }
    }
    memoL[i] = res;
    return res;
}

vector<string> tokenize(const string &s) {
    vector<string> ret;
    istringstream iss(s);
    string token;
    while(iss >> token) {
        while(!token.empty() && token.back()==','){
            token.pop_back();
            ret.push_back(token);
            ret.push_back(",");
            token = "";
        }
        if(!token.empty()) ret.push_back(token);
    }
    return ret;
}

int main(){
    ios::sync_with_stdio(0);
    cin.tie(0);

    int N; cin >> N;
    cin.ignore();
    for(int tc=0; tc<N; tc++){
        string line;
        getline(cin, line);
        T = tokenize(line);
        memoS.clear(); memoE.clear(); memoL.clear(); memoList.clear();
        MapAns mS = parseS(0);
        Ans finalAns; finalAns.valid = false;
        for(auto &pr : mS) {
            if(pr.first == (int)T.size() && pr.second.valid) {
                finalAns = mergeAns(finalAns, pr.second);
            }
        }
        if(finalAns.valid && !finalAns.amb) cout << finalAns.s << endl;
        else cout << "AMBIGUOUS" << endl;
    }
    return 0;
}
accuracy: 1
time_ms: 280
memory_kb: 19940
final_rank: 4

code_snippet: #include <cstdio>
#include <cctype>
#include <cassert>
#include <string>
#include <vector>
#include <algorithm>
#include <map>
#include <functional>

void preprocess(const std::string &s, std::vector<std::string> &t) {
  t.clear();
  for (size_t i=0; i<s.length(); ++i) {
    if (s[i] == 'a') {
      if (s[i+1] == ' ') {
        // "a list of "
        t.push_back("(");
        i += 9;
      } else if (s[i+1] == 'n') {
        // "and "
        t.push_back("&");
        i += 3;
      } else {
        assert(false);
      }
      continue;
    }

    std::string word(1, s[i]);
    while (++i < s.length() && isupper(s[i]))
      word += s[i];

    t.push_back(word);
    if (i < s.length() && s[i] == ',') {
      ++i;
    }
  }
}

void debug(const std::vector<std::string> &s) {
  fprintf(stderr, "> ");
  for (size_t i=0; i<s.size(); ++i)
    fprintf(stderr, "%s%c", s[i].c_str(), i+1<s.size()? ' ':'\n');
}

std::string cyk(const std::vector<std::string> &s) {
  /*
     S-Expr   -> "(" Element
               | "(" Elements
     Element  -> Upper
               | S-Expr
     Elements -> Element "and" Element
               | Element Elements
     ---

     S-Expr     -> "(" Elements
                 | "(" Upper
                 | "(" S-Expr
     Elements   -> Upper Elements
                 | Upper AndElement
                 | S-Expr Elements
                 | S-Expr AndElement
     AndElement -> "and" Upper
                 | "and" S-Expr
   */ 
  enum Symbol {
    INVALID,
    // non-terminals
    S_EXPR, ELEMS, AND_ELEM,
    // terminals
    PAREN=9, AND, UPPER,
  };
  std::vector<std::string> types={
    "0", "S-expr", "Elems", "AndElem",
    "0", "0", "0", "0", "0", "\"(\"", "\"and\"", "[A-Z]+"
  };
  
  auto category=[](const std::string &token) {
    if (token == "(") return PAREN;
    if (token == "&") return AND;
    if (isupper(token[0])) return UPPER;
    return INVALID;
  };

  std::vector<Symbol> term={PAREN, AND, UPPER};
  std::vector<std::vector<Symbol>> prod={
    {S_EXPR, PAREN, ELEMS},
    {S_EXPR, PAREN, UPPER},
    {S_EXPR, PAREN, S_EXPR},
    {ELEMS, UPPER, ELEMS},
    {ELEMS, UPPER, AND_ELEM},
    {ELEMS, S_EXPR, ELEMS},
    {ELEMS, S_EXPR, AND_ELEM},
    {AND_ELEM, AND, UPPER},
    {AND_ELEM, AND, S_EXPR},
  };

  std::vector<std::vector<std::vector<int>>> dp(
      s.size(), std::vector<std::vector<int>>(
        s.size(), std::vector<int>(prod.size()+term.size())));

  for (size_t i=0; i<s.size(); ++i) {
    Symbol cat=category(s[i]);
    if (cat != INVALID) {
      dp[0][i][cat] = 1;
    }
  }

  struct Left {
    size_t length, pos;
    Symbol symb;
    Left(size_t i, size_t j, Symbol a): length(i), pos(j), symb(a) {}
    bool operator <(const Left &oth) const {
      if (length != oth.length) return length < oth.length;
      if (pos != oth.pos) return pos < oth.pos;
      return symb < oth.symb;
    }
  };

  struct Right {
    size_t part;
    Symbol symb1, symb2;
    Right(size_t k, Symbol b, Symbol c): part(k), symb1(b), symb2(c) {}
  };

  std::map<Left, Right> via;
  size_t n=s.size();
  for (size_t i=1; i<n; ++i) {
    for (size_t j=0; j<n-i; ++j) {
      for (size_t k=1; k<=i; ++k) {
        for (const auto &pp: prod) {
          Symbol a=pp[0], b=pp[1], c=pp[2];
          if (dp[k-1][j][b] && dp[i-k][j+k][c]) {
            dp[i][j][a] += std::max(dp[k-1][j][b], dp[i-k][j+k][c]);
            if (dp[i][j][a] > 2) dp[i][j][a] = 2;
            via.emplace(Left(i, j, a), Right(k, b, c));
          }
        }
      }
    }
  }
  if (dp[n-1][0][1] > 1) return "AMBIGUOUS";

  assert(dp[n-1][0][1]);
  std::function<std::string (Left)> dfs=[&](const Left &left) {
    if (left.length == 0) return s[left.pos];
    Right right=via.at(left);
    size_t i=left.length, j=left.pos, k=right.part;
    Symbol a=left.symb, b=right.symb1, c=right.symb2;

    std::string sb=dfs(Left(k-1, j, b)), sc=dfs(Left(i-k, j+k, c));

    if (a == S_EXPR) {
      return sb + sc + ")";
    } else if (a == ELEMS) {
      return sb + " " + sc;
    } else if (a == AND_ELEM) {
      assert(sb == "&");
      return sc;
    } else {
      assert(false);
    }
  };
  return dfs(Left(n-1, 0, S_EXPR));
}

void solve_testcase() {
  char buf[1024];
  scanf("\n%[^\n]", buf);
  std::string s=buf;
  std::vector<std::string> t;
  preprocess(s, t);
  printf("%s\n", cyk(t).c_str());
}

int main() {
  int N;
  scanf("%d", &N);
  for (int i=0; i<N; ++i)
    solve_testcase();
}
accuracy: 1
time_ms: 6450
memory_kb: 12072
final_rank: 6

code_snippet: #include "bits/stdc++.h"
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
#define rep(i,n) for(ll i=0;i<(ll)(n);i++)
#define pb push_back
#define vi vector<int>
#define vvi vector<vi>
#define va vector<array<int,6>>
#define vva vector<va>

vector<string> toVs(string s){
	vector<string> ret;
	string buf = "";
	
	rep(i,s.size()){
		if(i+9<=s.size()&&s.substr(i,9)=="a list of"){
			buf+="<";
			i+=8;
		}
		else if(i+3<=s.size()&&s.substr(i,3)=="and"){
			buf+="&";
			i+=2;
		}
		else if(isalpha(s[i]))buf+=s[i];
		else if(s[i]==' '){
			ret.pb(buf);
			buf = "";
		}
	}
	if(buf.size())ret.pb(buf);
	return ret;
}


vector<char> toWordClass(vector<string> vs){
	vector<char> ret;
	rep(i,vs.size()){
		string s = vs[i];
		if(s=="<")ret.pb('L');
		else if(s=="&")ret.pb('A');
		else ret.pb('T');
	}
	return ret;
}


deque<string> dfs(int a,int b,int c,vector<vva> &bef,vector<string> &vs){
	if(a==b){
		if(vs[a]=="<"||vs[a]=="&")return deque<string>();
		deque<string> ret;
		ret.push_back(vs[a]);
		return ret;
	}
	
	array<int,3> l,r;
	rep(i,3)l[i] = bef[a][b][c][i];
	rep(i,3)r[i] = bef[a][b][c][i+3];
	
	deque<string> ret,y;
	ret = dfs(l[0],l[1],l[2],bef,vs);
	y   = dfs(r[0],r[1],r[2],bef,vs);
	
	for(auto &e:y){
		ret.push_back(e);
	}
	
	if(c==0){
		ret.push_front("(");
		ret.push_back(")");
	}
	
	return ret;
}


int main(){
	vector<pii> rule[3] = {
		{pii(4,3),pii(4,0),pii(4,1)},			//S
		{pii(3,2),pii(0,2),pii(3,1),pii(0,1)},	//P
		{pii(5,3),pii(5,0)}						//Q
	};
	
	int n;
	cin>>n;
	cin.ignore();
	while(n--){
		string s;
		getline(cin,s);
		vector<string> vs = toVs(s);
		int N = vs.size();
		vector<char> wc = toWordClass(vs);
		
		vector<vvi> dp(N,vvi(N,vi(6,0)));
		vector<vva> bef(N,vva(N,va(6,array<int,6>{-1,-1,-1,-1,-1,-1})));
		
		rep(i,N){
			if(wc[i]=='T')dp[i][i][3]=1;
			if(wc[i]=='L')dp[i][i][4]=1;
			if(wc[i]=='A')dp[i][i][5]=1;
		}
		
		for(int wid = 2;wid<=N;wid++){
			for(int l = 0;l<N;l++){
				int r = l+wid-1;
				if(r>=N)continue;
				rep(i,3){
					for(int p = l;p<=r-1;p++){
						rep(j,rule[i].size()){
							int x,y;
							tie(x,y) = rule[i][j];
							if(dp[l][p][x]!=0 && dp[p+1][r][y]!=0){
								dp[l][r][i]+=dp[l][p][x]*dp[p+1][r][y];
								if(dp[l][r][i]>2)dp[l][r][i] = 2;
								bef[l][r][i] = array<int,6>{l,p,x,p+1,r,y};
							}
						}
					}
				}
			}
		}
		
		if(dp[0][N-1][0]>=2){
			cout<<"AMBIGUOUS"<<endl;
			continue;
		}
		assert(dp[0][N-1][0]!=0);
		
		
		deque<string> ans = dfs(0,N-1,0,bef,vs);
		
		vector<string> a;
		for(auto &e:ans)a.pb(e);
		
		rep(i,a.size()){
			if(a[i]=="("||(i+1<a.size()&&a[i+1]==")")||i==a.size()-1)cout<<a[i];
			else cout<<a[i]<<" ";
		}
		cout<<endl;
	}
}
accuracy: 1
time_ms: 5110
memory_kb: 29164
final_rank: 7

code_snippet: #include <vector>
#include <iostream>
#include <utility>
#include <algorithm>
#include <string>
#include <deque>
#include <tuple>
#include <queue>
#include <functional>
#include <cmath>
#include <iomanip>
#include <map>
#include <numeric>
#include <unordered_map>
#include <unordered_set>
#include <complex>
#include <iterator>
#include <array>
#include <chrono>
//cin.sync_with_stdio(false);
//streambuf
using namespace std;
typedef long long ll;
typedef long double ld;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
typedef pair<double, double> pdd;
using vi = vector<int>;
using vll = vector<ll>;
using vpii = vector<pii>;
template<class T, int s>using va = vector<array<T, s>>;
template<class T, class T2> using umap = unordered_map<T, T2>;
template<class T> using uset = unordered_set<T>;
template<class T, class S> void cmin(T &a, const S&&b) { if (a > b)a = b; }
template<class T, class S> void cmax(T &a, const S&&b) { if (a < b)a = b; }
#define ALL(a) a.begin(),a.end()
#define rep(i,a) for(int i=0;i<a;i++)
#define rep1(i,a) for(int i=1;i<=a;i++)
#define rrep(i,a) for(int i=a-1;i>=0;i--)
#define rrep1(i,a) for(int i=a;i;i--)
const ll mod = 1000000007;
#ifndef INT_MAX
const int INT_MAX = numeric_limits<signed>().max();
#endif
template<class T>using heap = priority_queue<T, vector<T>, greater<T>>;
template<class T>using pque = priority_queue<T, vector<T>, function<T(T, T)>>;
template <class T>
inline void hash_combine(size_t & seed, const T & v) {
	hash<T> hasher;
	seed ^= hasher(v) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
}
namespace std {

	template<typename S, typename T> struct hash<pair<S, T>> {
		inline size_t operator()(const pair<S, T> & v) const {
			size_t seed = 0;
			hash_combine(seed, v.first);
			hash_combine(seed, v.second);
			return seed;
		}
	};
	// Recursive template code derived from Matthieu M.
	template <class Tuple, size_t Index = std::tuple_size<Tuple>::value - 1>
	struct HashValueImpl
	{
		static void apply(size_t& seed, Tuple const& tuple)
		{
			HashValueImpl<Tuple, Index - 1>::apply(seed, tuple);
			hash_combine(seed, std::get<Index>(tuple));
		}
	};

	template <class Tuple>
	struct HashValueImpl<Tuple, 0>
	{
		static void apply(size_t& seed, Tuple const& tuple)
		{
			hash_combine(seed, std::get<0>(tuple));
		}
	};

	template <typename ... TT>
	struct hash<std::tuple<TT...>>
	{
		size_t
			operator()(std::tuple<TT...> const& tt) const
		{
			size_t seed = 0;
			HashValueImpl<std::tuple<TT...> >::apply(seed, tt);
			return seed;
		}

	};
}
ll pow(ll base, ll i, ll mod) {
	ll a = 1;
	while (i) {
		if (i & 1) {
			a *= base;
			a %= mod;
		}
		base *= base;
		base %= mod;
		i /= 2;
	}
	return a;
}
class unionfind {
	vector<int> par, rank, size_;//????????§??????????????¢???????????????????????????rank???????????????size?????????
public:
	unionfind(int n) :par(n), rank(n), size_(n, 1) {
		iota(ALL(par), 0);
	}
	int find(int x) {
		if (par[x] == x)return x;
		return par[x] = find(par[x]);
	}
	void unite(int x, int y) {
		x = find(x), y = find(y);
		if (x == y)return;
		if (rank[x] < rank[y])swap(x, y);
		par[y] = x;
		size_[x] += size_[y];
		if (rank[x] == rank[y])rank[x]++;
	}
	bool same(int x, int y) {
		return find(x) == find(y);
	}
	int size(int x) {
		return size_[find(x)];
	}
};
ll gcd(ll a, ll b) {
	while (b) {
		ll c = a%b;
		a = b;
		b = c;
	}
	return a;
}
ll lcm(ll a, ll b) {
	return a / gcd(a, b)*b;
}
int popcnt(unsigned long long a) {
	a = (a & 0x5555555555555555) + (a >> 1 & 0x5555555555555555);
	a = (a & 0x3333333333333333) + (a >> 2 & 0x3333333333333333);
	a = (a & 0x0f0f0f0f0f0f0f0f) + (a >> 4 & 0x0f0f0f0f0f0f0f0f);
	a = (a & 0x00ff00ff00ff00ff) + (a >> 8 & 0x00ff00ff00ff00ff);
	a = (a & 0x0000ffff0000ffff) + (a >> 16 & 0x0000ffff0000ffff);
	return (a & 0xffffffff) + (a >> 32);
}
template<class T, class Func = function<T(T, T)>>
class segtree {
	vector<T> obj;
	int offset;
	Func updater;
	T e;
	int bufsize(int num) {
		int i = 1;
		for (; num >i; i <<= 1);
		offset = i - 1;
		return (i << 1) - 1;
	}
	T query(int a, int b, int k, int l, int r) {
		if (r <= a || b <= l)return e;
		if (a <= l && r <= b)return obj[k];
		else return updater(query(a, b, k * 2 + 1, l, (l + r) / 2), query(a, b, k * 2 + 2, (l + r) / 2, r));
	}
public:
	T query(int a, int b) {//[a,b)
		return query(a, b, 0, 0, offset + 1);
	}
	void updateall(int l = 0, int r = -1) {
		if (r < 0)r = offset + 1;
		l += offset, r += offset;
		do {
			l = l - 1 >> 1, r = r - 1 >> 1;
			for (int i = l; i < r; i++)obj[i] = updater(obj[i * 2 + 1], obj[i * 2 + 2]);
		} while (l);
	}
	void update(int k, T &a) {
		k += offset;
		obj[k] = a;
		while (k) {
			k = k - 1 >> 1;
			obj[k] = updater(obj[k * 2 + 1], obj[k * 2 + 2]);
		}
	}
	segtree(int n, T e, const Func &updater_ = Func()) :obj(bufsize(n), e), e(e), updater(updater_) {}
	segtree(vector<T> &vec, T e, const Func &updater = Func()) :obj(bufsize(vec.size()), e), e(e), updater(updater) {
		copy(vec.begin(), vec.end(), obj.begin() + offset);
		updateall();
	}
	typename vector<T>::reference operator[](int n) {
		return obj[n + offset];
	}
};
template<class T>
class matrix {
	vector<vector<T>> obj;
	pair<int, int> s;
public:
	matrix(pair<int, int> size, T e = 0) :matrix(size.first, size.second, e) {}
	matrix(int n, int m = -1, T e = 0) :obj(n, vector<T>(m == -1 ? n : m, e)), s(n, m == -1 ? n : m) {}
	static matrix e(int n) {
		matrix a = (n);
		for (int i = 0; i < n; i++)a[i][i] = 1;
		return a;
	}
	matrix& operator+=(const matrix &p) {
		if (s != p.s)throw runtime_error("matrix error");
		for (int i = 0; i < s.first; i++)
			for (int j = 0; j < s.second; j++)obj[i][j] += p.obj[i][j];
		return *this;
	}
	matrix operator+(const matrix &p) {
		matrix res(*this);
		return res += p;
	}
	matrix& operator-=(const matrix &p) {
		if (s != p.s)throw runtime_error("matrix error");
		for (int i = 0; i < s.first; i++)
			for (int j = 0; j < s.second; j++)obj[i][j] -= p.obj[i][j];
		return *this;
	}
	matrix operator-(const matrix &p) {
		matrix res(*this);
		return res -= p;
	}
	matrix& operator*=(T p) {
		for (auto &a : obj)
			for (auto &b : a)b *= p;
		return *this;
	}
	matrix operator*(T p) {
		matrix res(*this);
		return res *= p;
	}
	matrix operator*(const matrix &p) {
		if (s.second != p.s.first)throw runtime_error("matrix error");
		matrix ret(s.first, p.s.second);
		for (int i = 0; i < s.first; i++)
			for (int j = 0; j < s.second; j++)
				for (int k = 0; k < p.s.second; k++)ret[i][k] += obj[i][j] * p.obj[j][k];
		return ret;
	}
	matrix &operator*=(const matrix &p) {
		return *this = *this*p;
	}
	pair<int, int> size() const {
		return s;
	}
	matrix &mod(T m) {
		for (auto &a : obj)
			for (auto &b : a)b %= m;
		return *this;
	}
	typename vector<vector<T>>::reference operator[](int t) {
		return obj[t];
	}
};
template<class T> inline
matrix<T> pow(matrix<T> &base, unsigned exp) {
	auto base_(base);
	if (base_.size().first != base_.size().second)throw runtime_error("matrix error");
	matrix<T> res = matrix<T>::e(base_.size().first);
	for (;;) {
		if (exp & 1)res *= base_;
		if (!(exp /= 2))break;
		base_ *= base_;
	}
	return res;
}
template<class T> inline
matrix<T> modpow(matrix<T> &base, unsigned exp, T m) {
	auto base_(base);
	if (base.size().first != base_.size().second)throw runtime_error("matrix error");
	matrix<T> res = matrix<T>::e(base_.size().first);
	for (;;) {
		if (exp & 1)(res *= base_).mod(m);
		if (!(exp /= 2))break;
		(base_ *= base_).mod(m);
	}
	return res;
}
template<class T>int id(vector<T> &a, T b) {
	return lower_bound(ALL(a), b) - a.begin();
}
class Flow {
	int V;
	struct edge { int to, cap, rev, cost; };
	vector<vector<edge>> G;
	vector<int> level, iter, h, dist, prevv, preve;
	Flow(int size) :G(size + 1), V(size + 1) {
	}
	void add_edge(int from, int to, int cap, int cost = 0) {
		G[from].push_back(edge{ to, cap, (int)G[to].size(),cost });
		G[to].push_back(edge{ from,0,(int)G[from].size() - 1,-cost });
	}
	void bfs(int s) {
		fill(level.begin(), level.end(), -1);
		queue<int> que;
		level[s] = 0;
		que.push(s);
		while (!que.empty()) {
			int v = que.front(); que.pop();
			for (int i = 0; i < G[v].size(); i++) {
				edge &e = G[v][i];
				if (e.cap > 0 && level[e.to] < 0) {
					level[e.to] = level[v] + 1;
					que.push(e.to);
				}
			}
		}
	}
	int dfs(int v, int t, int f) {
		if (v == t)return f;
		for (int &i = iter[v]; i < G[v].size(); i++) {
			edge &e = G[v][i];
			if (e.cap > 0 && level[v] < level[e.to]) {
				int d = dfs(e.to, t, min(f, e.cap));
				if (d > 0) {
					e.cap -= d;
					G[e.to][e.rev].cap += d;
					return d;
				}
			}
		}
		return 0;
	}
	int max_flow(int s, int t) {
		level.resize(V);
		iter.resize(V);
		int flow = 0;
		for (;;) {
			bfs(s);
			if (level[t] < 0)return flow;
			fill(iter.begin(), iter.end(), 0);
			int f;
			while ((f = dfs(s, t, numeric_limits<int>::max()))>0) {
				flow += f;
			}
		}
	}
	typedef pair<int, int> P;
	int min_cost_flow(int s, int t, int f) {
		int res = 0;
		h.resize(V);
		dist.resize(V);
		prevv.resize(V);
		preve.resize(V);
		fill(h.begin(), h.end(), 0);
		while (f > 0) {
			priority_queue<P, vector<P>, greater<P>> que;
			fill(dist.begin(), dist.end(), numeric_limits<int>::max());
			dist[s] = 0;
			que.push({ 0,s });
			while (!que.empty()) {
				P p = que.top(); que.pop();
				int v = p.second;
				if (dist[v] < p.first)continue;
				for (int i = 0; i < G[v].size(); i++) {
					edge &e = G[v][i];
					if (e.cap > 0 && dist[e.to]>dist[v] + e.cost + h[v] - h[e.to]) {
						dist[e.to] = dist[v] + e.cost + h[v] - h[e.to];
						prevv[e.to] = v;
						preve[e.to] = i;
						que.push({ dist[e.to],e.to });
					}
				}
			}
			if (dist[t] == numeric_limits<int>::max()) {
				return -1;
			}
			for (int v = 0; v < V; v++)h[v] += dist[v];

			int d = f;
			for (int v = t; v != s; v = prevv[v]) {
				d = min(d, G[prevv[v]][preve[v]].cap);
			}
			f -= d;
			res += d*h[t];
			for (int v = t; v != s; v = prevv[v]) {
				edge &e = G[prevv[v]][preve[v]];
				e.cap -= d;
				G[v][e.rev].cap += d;
			}
		}
		return res;
	}
};
const ld eps = 1e-11, pi = acos(-1.0);
typedef complex<ld> P;
typedef vector<P> VP;
ld dot(P a, P b) { return real(conj(a) * b); }
ld cross(P a, P b) { return imag(conj(a) * b); }

namespace std {
	bool operator<(const P &a, const P &b) {
		return abs(a.real() - b.real()) < eps ? a.imag() < b.imag() : a.real() < b.real();
	}
}

struct L { P a, b; };//line->l,segment->s
struct C { P p; ld r; };

int ccw(P a, P b, P c) {
	b -= a; c -= a;
	if (cross(b, c) > eps) return 1;   // counter clockwise
	if (cross(b, c) < -eps) return -1; // clockwise
	if (dot(b, c) < 0) return 2;       // c--a--b on line
	if (norm(b) < norm(c)) return -2;  // a--b--c on line
	return 0;                          // a--c--b on line
}

bool isis_ll(L l, L m) {//is intersect
	return abs(cross(l.b - l.a, m.b - m.a)) > eps;
}

bool isis_ls(L l, L s) {
	ld a = cross(l.b - l.a, s.a - l.a);
	ld b = cross(l.b - l.a, s.b - l.a);
	return (a * b < eps);
}

bool isis_lp(L l, P p) {
	return abs(cross(l.b - p, l.a - p)) < eps;
}

bool isis_ss(L s, L t) {
	return ccw(s.a, s.b, t.a) * ccw(s.a, s.b, t.b) <= 0 &&
		ccw(t.a, t.b, s.a) * ccw(t.a, t.b, s.b) <= 0;
}

P is_ll(L s, L t) { //intersect
	P sv = s.b - s.a, tv = t.b - t.a;
	return s.a + sv * cross(tv, t.a - s.a) / cross(tv, sv);
}

bool isis_sp(L s, P p) {
	return abs(s.a - p) + abs(s.b - p) - abs(s.b - s.a) < eps;
}

P proj(L l, P p) {
	ld t = dot(p - l.a, l.a - l.b) / norm(l.a - l.b);
	return l.a + t * (l.a - l.b);
}

ld dist_lp(L l, P p) {
	return abs(p - proj(l, p));
}

ld dist_ll(L l, L m) {
	return isis_ll(l, m) ? 0 : dist_lp(l, m.a);
}

ld dist_ls(L l, L s) {
	if (isis_ls(l, s)) return 0;
	return min(dist_lp(l, s.a), dist_lp(l, s.b));
}

ld dist_sp(L s, P p) {
	P r = proj(s, p);
	if (isis_sp(s, r)) return abs(r - p);
	return min(abs(s.a - p), abs(s.b - p));
}

ld dist_ss(L s, L t) {
	if (isis_ss(s, t)) return 0;
	ld a = min(dist_sp(s, t.a), dist_sp(t, s.a));
	ld b = min(dist_sp(s, t.b), dist_sp(t, s.b));
	return min(a, b);
}

VP is_cc(C c1, C c2) {
	VP res;
	ld d = abs(c1.p - c2.p);
	ld rc = (d * d + c1.r * c1.r - c2.r * c2.r) / (2 * d);
	ld dfr = c1.r * c1.r - rc * rc;
	if (abs(dfr) < eps) dfr = 0.0;
	else if (dfr < 0.0) return res; // no intersection
	ld rs = sqrt(dfr);
	P diff = (c2.p - c1.p) / d;
	res.push_back(c1.p + diff * P(rc, rs));
	if (dfr != 0.0) res.push_back(c1.p + diff * P(rc, -rs));
	return res;
}

bool isis_vc(vector<C> vc) {
	VP crs;
	int n = vc.size();
	rep(i, n)rep(j, i)
		for (P p : is_cc(vc[i], vc[j]))
			crs.push_back(p);
	rep(i, n)
		crs.push_back(vc[i].p);
	for (P p : crs) {
		bool valid = true;
		rep(i, n)
			if (abs(p - vc[i].p)>vc[i].r + eps)
				valid = false;
		if (valid) return true;
	}
	return false;
}

VP is_lc(C c, L l) {
	VP res;
	ld d = dist_lp(l, c.p);
	if (d < c.r + eps) {
		ld len = (d > c.r) ? 0.0 : sqrt(c.r * c.r - d * d); //safety;
		P nor = (l.a - l.b) / abs(l.a - l.b);
		res.push_back(proj(l, c.p) + len * nor);
		res.push_back(proj(l, c.p) - len * nor);
	}
	return res;
}

VP is_sc(C c, L l) {
	VP v = is_lc(c, l), res;
	for (P p : v)
		if (isis_sp(l, p)) res.push_back(p);
	return res;
}

vector<L> tangent_cp(C c, P p) {//????????\????
	vector<L> ret;
	P v = c.p - p;
	ld d = abs(v);
	ld l = sqrt(norm(v) - c.r * c.r);
	if (isnan(l)) { return ret; }
	P v1 = v * P(l / d, c.r / d);
	P v2 = v * P(l / d, -c.r / d);
	ret.push_back(L{ p, p + v1 });
	if (l < eps) return ret;
	ret.push_back(L{ p, p + v2 });
	return ret;
}

vector<L> tangent_cc(C c1, C c2) {
	vector<L> ret;
	if (abs(c1.p - c2.p) - (c1.r + c2.r) > -eps) {
		P center = (c1.p * c2.r + c2.p * c1.r) / (c1.r + c2.r);
		ret = tangent_cp(c1, center);
	}
	if (abs(c1.r - c2.r) > eps) {
		P out = (-c1.p * c2.r + c2.p * c1.r) / (c1.r - c2.r);
		vector<L> nret = tangent_cp(c1, out);
		ret.insert(ret.end(), ALL(nret));
	}
	else {
		P v = c2.p - c1.p;
		v /= abs(v);
		P q1 = c1.p + v * P(0, 1) * c1.r;
		P q2 = c1.p + v * P(0, -1) * c1.r;
		ret.push_back(L{ q1, q1 + v });
		ret.push_back(L{ q2, q2 + v });
	}
	return ret;
}

ld area(const VP &p) {//??¢?????
	ld res = 0;
	int n = p.size();
	rep(j, n) res += cross(p[j], p[(j + 1) % n]);
	return res / 2;
}

bool is_polygon(L l, VP &g) {
	int n = g.size();
	for (int i = 0; i < n; i++) {
		P a = g[i];
		P b = g[(i + 1) % n];
		if (isis_ss(l, L{ a, b })) return true;
	}
	return false;
}

int is_in_Polygon(const VP &g, P p) {
	bool in = false;
	int n = g.size();
	for (int i = 0; i < n; i++) {
		P a = g[i] - p, b = g[(i + 1) % n] - p;
		if (imag(a) > imag(b)) swap(a, b);
		if (imag(a) <= 0 && 0 < imag(b))
			if (cross(a, b) < 0) in = !in;
		if (abs(cross(a, b)) < eps && dot(a, b) < eps) return 0; // on
	}
	if (in) return 1; // in
	return -1; // out
}

VP ConvexHull(VP ps) {
	int n = ps.size();
	int k = 0;
	sort(ps.begin(), ps.end());
	VP ch(2 * n);
	for (int i = 0; i < n; ch[k++] = ps[i++])
		while (k >= 2 && ccw(ch[k - 2], ch[k - 1], ps[i]) <= 0) --k;
	for (int i = n - 2, t = k + 1; i >= 0; ch[k++] = ps[i--])
		while (k >= t && ccw(ch[k - 2], ch[k - 1], ps[i]) <= 0) --k;
	ch.resize(k - 1);
	return ch;
}

VP ConvexCut(const VP &ps, L l) {
	VP Q;
	for (int i = 0; i < (int)ps.size(); i++) {
		P A = ps[i], B = ps[(i + 1) % ps.size()];
		if (ccw(l.a, l.b, A) != -1) Q.push_back(A);
		if (ccw(l.a, l.b, A) * ccw(l.a, l.b, B) < 0)
			Q.push_back(is_ll(L{ A, B }, l));
	}
	return Q;
}
double dist2(P a) {
	return real(a)*real(a) + imag(a)*imag(a);
}
// Suffix Array	?????????O(|S|log^2|S|), ????´¢O(|T|log|S|), ?????????????§????O(|S|)
class StringSearch {
	const int n;
	string S;
public:
	vector<int> sa, rank;
	StringSearch(const string &S_) :n(S_.size()), S(S_), sa(n + 1), rank(n + 1) {
		for (int i = 0; i <= n; i++) {
			sa[i] = i;
			rank[i] = i < n ? S[i] : -1;
		}
		vector<int> tmp(n + 1);
		for (int k = 1; k <= n; k *= 2) {
			auto Compare_SA = [=](int i, int j) {
				if (this->rank[i] != this->rank[j]) return this->rank[i] < this->rank[j];

				int ri = i + k <= n ? this->rank[i + k] : -1;
				int rj = j + k <= n ? this->rank[j + k] : -1;
				return ri < rj;
			};
			sort(sa.begin(), sa.end(), Compare_SA);
			tmp[sa[0]] = 0;
			for (int i = 1; i <= n; i++) {
				tmp[sa[i]] = tmp[sa[i - 1]] + (Compare_SA(sa[i - 1], sa[i]) ? 1 : 0);
			}
			for (int i = 0; i <= n; i++) {
				this->rank[i] = tmp[i];
			}
		}
	}
	bool Contain(const string &T) {
		int a = 0, b = n;
		while (b - a > 1) {
			int c = (a + b) / 2;
			if (S.compare(sa[c], T.length(), T) < 0) a = c;
			else b = c;
		}
		return S.compare(sa[b], T.length(), T) == 0;
	}
	vector<int> LCPArray() {
		for (int i = 0; i <= n; i++) rank[sa[i]] = i;
		int h = 0;
		vector<int> lcp(n + 1);
		for (int i = 0; i < n; i++) {
			int j = sa[rank[i] - 1];
			if (h > 0) h--;
			for (; j + h < n && i + h < n; h++) {
				if (S[j + h] != S[i + h]) break;
			}
			lcp[rank[i] - 1] = h;
		}
		return lcp;
	}
};
//0l 
//1A
//141
//101
//2a
//301
//331
//432
int dp[340][340][5];
vector<string> t;
string f4(int i, int j);
string f1(int i, int j) {
	if (i == j)return t[i];
	rep(k, j - i) {
		if (dp[i][k][4] && dp[i + k + 1][j - k - 1 - i][1])return f4(i, i + k) + f1(i + k + 1, j) + ')';
		if (dp[i][k][0] && dp[i + k + 1][j - k - 1 - i][1])return '(' + f1(i + k + 1, j) + ')';
	}
	return "";
}
string f3(int i, int j) {
	rep(k, j - i) {
		if (dp[i][k][0] && dp[i + k + 1][j - k - 1-i][1])return '(' + f1(i + k + 1, j);
		if (dp[i][k][3] && dp[i + k + 1][j - k - 1-i][1])return f3(i, i + k) + " " + f1(i + k + 1, j);
	}
	return "";
}
string f4(int i, int j) {
	rep(k, j - i) {
		if (dp[i][k][3] && dp[i + k + 1][j - k - 1-i][2])return f3(i, i + k) + " ";
	}
}
int main() {
	int n;
	cin >> n;
	string tmp;
	getline(cin, tmp);
	while (n--) {
		string s;
		getline(cin, s);
		t.clear();
		rep(i, s.size()) {
			if (s[i] >= 'A'&&s[i] <= 'Z') {
				tmp = "";
				while (s[i] >= 'A'&&s[i] <= 'Z')tmp += s[i++];
				t.push_back(tmp);
			}
			if (s[i] == 'l'&&s[i + 1] == 'i')t.push_back("l");
			if (s[i] == 'a'&&s[i + 1] == 'n')t.push_back("a");
		}
		fill(dp[0][0], dp[340][0], 0);
		rep(i, t.size())dp[i][0][(t[i] == "l" ? 0 : t[i] == "a" ? 2 : 1)] = 1;
		rep1(i, t.size() - 1) {
			rep(j, t.size() - i) {
				rep(k, i) {
					dp[j][i][1] = min(dp[j][i][1] + dp[j][k][4] * dp[j + k + 1][i - k - 1][1] + dp[j][k][0] * dp[j + k + 1][i - k - 1][1], 20000);
					dp[j][i][4] = min(dp[j][i][4] + dp[j][k][3] * dp[j + k + 1][i - k - 1][2], 20000);
					dp[j][i][3] = min(dp[j][i][3] + dp[j][k][0] * dp[j + k + 1][i - k - 1][1] + dp[j][k][3] * dp[j+k+1][i - k - 1][1], 20000);
				}
			}
		}
		if (dp[0][t.size() - 1][1] == 1) {
			cout << f1(0, t.size() - 1) << endl;
		}
		else cout << "AMBIGUOUS" << endl;
	}
}
accuracy: 1
time_ms: 1990
memory_kb: 5344
final_rank: 3

code_snippet: #include<bits/stdc++.h>

#define REP(i,s,n) for(int i=s;i<n;i++)
#define rep(i,n) REP(i,0,n)

using namespace std;

typedef pair<int,int> ii;

const string FAIL = "AMBIGUOUS";
int dp[1000][1000][6]; // dp[][][0] -> the number of L, dp[][][1] -> A, dp[][][2] -> T, dp[][][3] -> S, dp[][][4] -> P, dp[][][5] -> Q
int path[1000][1000][6]; // 2??\????????´???????????????????????????????????????????????????????????????AMBIGUOUS????????????????????????
int topv[1000][1000][6];
int rigv[1000][1000][6];

/*
  ????§??¨???? S
  L ::= "list"
  A ::= "and"
  T ::= "A" | "B" | ... | "Z"
  S ::= L E | L P
  E ::= T | S
  P ::= E A E | E P
  
  -> Chomsky  Normal Form
  L ::= "list"
  A ::= "and"
  T ::= "A" | "B" | ... | "Z" <- ??¬??\??§????????°?????\???????????????????????????????????????????????????????????\??????????????????????????§?????????????????????
  S ::= L P | L T | L S
  P ::= T P | S P | T Q | S Q
  Q ::= A T | A S 
  
 */

vector<string> alphas;
vector<char> lexer(string context){
  vector<char> vec;
  rep(i,(int)context.size()) if( context[i] == ',' ) context[i] = ' ';
  stringstream ss;
  ss << context;
  string token;
  while( !( ss >> token ).fail() ){
    if( token == "a" || token[0] == 'o' ) continue;
    alphas.push_back("$");
    if( token[0] == 'l' )      vec.push_back('L'); // List
    else if( token[0] == 'a' ) vec.push_back('A'); // And
    else {
      vec.push_back('T'); // Terminal
      alphas.back() = token;
    }
  }
  return vec;
}

inline int getType(char c) { 
  return ( c == 'L' ) ? 0 : ( ( c == 'A' ) ? 1 : ( ( 'A' <= c && c <= 'Z' ) ? 2 : ( ( c == 'S' ) ? 3 : ( ( c == 'P' ) ? 4 : 5  ) ) ) );
}

inline int reduce(int a,int b) {
  if( a == 0 && b == 4 ) return 3; // S ::= L P
  if( a == 0 && b == 2 ) return 3; // S ::= L T
  if( a == 0 && b == 3 ) return 3; // S ::= L S
  if( a == 2 && b == 4 ) return 4; // P ::= T P
  if( a == 3 && b == 4 ) return 4; // P ::= S P
  if( a == 2 && b == 5 ) return 4; // P ::= T Q
  if( a == 3 && b == 5 ) return 4; // P ::= S Q
  if( a == 1 && b == 2 ) return 5; // Q ::= A T
  if( a == 1 && b == 3 ) return 5; // Q ::= A S
  return -1;
}

void dfs(int L,int R,int type,vector<ii> &buf){
  if( L == R ) return;
  if( type == 3 ) buf.push_back(ii(L,R));
  dfs(L,path[L][R][type],topv[L][R][type],buf);
  dfs(path[L][R][type]+1,R,rigv[L][R][type],buf);
}

const int LIMIT = 100;
void compute(string context){
  alphas.clear();
  vector<char> tokens = lexer(context);
  int n = tokens.size();
  rep(i,n) rep(j,n) rep(k,6) dp[i][j][k] = 0;
  rep(i,n) dp[i][i][getType(tokens[i])] = 1;
  for(int l=1;l<n;l++){
    for(int i=0;i+l<n;i++){
      int j = i + l;
      for(int k=i;k<j;k++){
	//dp[i][j] = dp[i][k] + dp[k+1][j]
	rep(tpv,6) if( dp[i][k][tpv] ) {
	  rep(riv,6) if( dp[k+1][j][riv] ) {
	    int response = reduce(tpv,riv);
	    if( response == -1 ) continue; // no such rule
	    dp[i][j][response] += dp[i][k][tpv] * dp[k+1][j][riv];
	    dp[i][j][response] = min(dp[i][j][response],LIMIT);
	    path[i][j][response] = k;
	    topv[i][j][response] = tpv;
	    rigv[i][j][response] = riv;
	  }
	}
      }
    }
  }
  
  assert( dp[0][n-1][3] >= 0LL );
  if( dp[0][n-1][3] > 1LL ) puts(FAIL.c_str());
  else {
    vector<ii> buf;
    dfs(0,n-1,3,buf);
    string answer = "";
    vector<int> pR(n,0),pL(n,0);
    rep(i,(int)buf.size()) ++pR[buf[i].second], ++pL[buf[i].first];
    rep(i,(int)alphas.size()) {
      answer += string(pL[i],'(');
      if( alphas[i] != "$" ) answer += "!"+alphas[i]+"?";
      answer += string(pR[i],')');
    }
    string new_answer = "";
    int p = 0;
    rep(i,(int)answer.size()) {
      if( answer[i] == '(' ) ++p;
      if( answer[i] == ')' ) --p;
      new_answer += answer[i];
      if( answer[i] == ')' || answer[i] == '?' ) {
	if( i+1 < (int)answer.size() && answer[i+1] == ')' ) continue;
	new_answer += " ";
      }
    }
    string new_answer3 = "";
    rep(i,(int)new_answer.size()-1) {
      if( new_answer[i] == '!' || new_answer[i] == '?' ) continue;
      if( i+1 < (int)new_answer.size() && new_answer[i] == '(' && new_answer[i+1] == ' ' ) continue;
      if( i+1 < (int)new_answer.size() && new_answer[i] == ' ' && new_answer[i+1] == ')' ) continue;
      new_answer3 += new_answer[i];
    }
    cout << new_answer3 << endl;
  }
}

int main(){
  /*
  int n = 5;
  for(int l=1;l<n;l++){
    for(int i=0;i+l<n;i++){
      int j = i + l;
      for(int k=i;k<j;k++){
	//dp[i][j] = dp[i][k] + dp[k+1][j]
	 cout << "[" << i << "," << j << "] = [" << i << "][" << k << "][" << k+1 << "][" << j << "]" << endl;
      }
    }
  }
  cout << "final => [" << 0 << "," << n-1 << "]" << endl;
  return 0;
  */
  int T;
  cin >> T;
  cin.ignore();
  while( T-- ) {
    string context;
    getline(cin,context);
    compute(context);
  }
  return 0;
}
accuracy: 1
time_ms: 3840
memory_kb: 39100
final_rank: 8

code_snippet: #include <iostream>
#include <cstdio>
#include <vector>
#include <deque>
#include <string>
#include <algorithm>
#include <cctype>
#include <cstring>
using namespace std;

int tbl[6][6] = {
	{-1, 1, 1, -1, -1, -1},
	{-1, -1, -1, -1, -1, -1},
	{-1, -1, -1, -1, -1, -1},
	{0, 0, -1, -1, -1, 0},
	{2, -1, -1, -1, -1, 2},
	{-1, 1, 1, -1, -1, -1},
};

int cnt[500][500][6];
int dat[500][500][6];
int lft[500][500][6];
int rgt[500][500][6];
vector<string> name;


void tostr(int i, int j, int t, bool space, string &res){
	if(cnt[i][j][t] != 1){ throw 0; }

	int k = dat[i][j][t];
	int x = lft[i][j][t];
	int y = rgt[i][j][t];

	if(t == 0){
		tostr(i, k, x, false, res);
		if(space){ res += ' '; }
		res += '(';
		tostr(k, j, y, false, res);
		res += ')';
	}
	else if(t == 1 || t == 2){
		tostr(i, k, x, space, res);
		tostr(k, j, y, true, res);
	}
	else if(t == 5){
		if(space){ res += ' '; }
		res += name[k];
	}
}


string solve(const string &s){
	memset(cnt, 0, sizeof cnt);
	name.clear();

	int n = 0;
	char buf[32] = {};
	for(int i = 0; i < s.size(); ++i){
		if(s[i] == 'l'){
			cnt[n][n+1][3] = 1;
			++n;
		}
		else if(s[i] == 'n'){
			cnt[n][n+1][4] = 1;
			++n;
		}
		else if(isupper(s[i])){
			sscanf(s.c_str() + i, "%[A-Z]", buf);
			cnt[n][n+1][5] = 1;
			dat[n][n+1][5] = name.size();
			name.push_back(buf);
			i += name.back().size() - 1;
			++n;
		}
	}

	for(int len = 2; len <= n; ++len){
		for(int i = 0; i + len <= n; ++i){
			int j = i + len;
			for(int k = i; k < i + len; ++k){
				for(int x = 0; x < 6; ++x){
					if(cnt[i][k][x] == 0){ continue; }
					for(int y = 0; y < 6; ++y){
						int t = tbl[x][y];
						if(cnt[k][j][y] == 0 || t == -1){ continue; }
						if(++cnt[i][j][t] == 1){
							dat[i][j][t] = k;
							lft[i][j][t] = x;
							rgt[i][j][t] = y;
						}
					}
				}
			}
		}
	}

	if(cnt[0][n][0] == 1){
		try{
			string ans;
			tostr(0, n, 0, false, ans);
			return ans;
		}catch(...){}
	}

	return "AMBIGUOUS";
}


int main(){
	name.reserve(500);

	int n;
	cin >> n;
	cin.get();
	string s;
	for(int i = 0; i < n; ++i){
		getline(cin, s);
		cout << solve(s) << '\n';
	}
}
accuracy: 1
time_ms: 3320
memory_kb: 24416
final_rank: 5

code_snippet: #include <iostream>
#include <sstream>
#include <string>
#include <algorithm>
#include <vector>
#include <stack>
#include <queue>
#include <set>
#include <map>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <cassert>

using namespace std;

#define FOR(i,k,n) for(int i=(k); i<(int)(n); ++i)
#define REP(i,n) FOR(i,0,n)
#define FORIT(i,c) for(__typeof((c).begin())i=(c).begin();i!=(c).end();++i)

template<class T> void debug(T begin, T end){ for(T i = begin; i != end; ++i) cerr<<*i<<" "; cerr<<endl; }
inline bool valid(int x, int y, int W, int H){ return (x >= 0 && y >= 0 && x < W && y < H); }

typedef long long ll;
const int INF = 100000000;
const double EPS = 1e-8;
const int MOD = 1000000007;
int dx[8] = {1, 0, -1, 0, 1, -1, -1, 1};
int dy[8] = {0, 1, 0, -1, 1, 1, -1, -1};
void replace(string& s, const string& from, const string& to){
  string::size_type pos = s.find(from);
  while(pos != string::npos){
    s.replace(pos, from.size(), to);
    pos = s.find(from, pos + to.size());
  }
}
struct Result{
  string value;
  int p;
  Result(string s, int p) : value(s), p(p){}
};
map<int, vector<Result> > memo[1000];
bool used[1000];
map<int, vector<Result> > expr(const string& s, int p){
  int P = p; 
  assert(P >= 0 && P < 1000);
  if(used[P]) return memo[P];
  assert(s[p] == '[');
  p++;
  queue<Result> que;
  map<int, vector<Result> >& res = memo[P];
  vector<int> cnt(s.size() + 1);
  if(isupper(s[p])){
    string word;
    while(isupper(s[p])) word += s[p++];
    Result r("(" + word, p);
    que.push(r);
    res[r.p].push_back(Result(r.value + ")", r.p));
  }else{
    map<int, vector<Result> > rvm = expr(s, p);
    FORIT(it_, rvm)FORIT(it, it_->second){
      que.push(Result("(" + it->value, it->p));
      res[it->p].push_back(Result("(" + it->value + ")", it->p));
    }
  }
  while(!que.empty()){
    Result r = que.front(); que.pop();
    if(s[r.p] == ','){
      if(s[r.p + 1] == '['){
        map<int, vector<Result> > rvm = expr(s, r.p + 1);
        FORIT(it_, rvm) FORIT(it, it_->second) if(cnt[it->p] < 2){
          cnt[it->p]++;
          que.push(Result(r.value + " " + it->value, it->p));
        }
      }else if(isupper(s[r.p + 1])){
        string word;
        while(isupper(s[r.p + 1])) word += s[++r.p];
        if(cnt[r.p + 1] < 2){
          cnt[r.p + 1]++;
          que.push(Result(r.value + " " + word, r.p + 1));
        }
      }else{
        assert(false);
      }
    }else if(s[r.p] == '&'){
      if(s[r.p + 1] == '['){
        map<int, vector<Result> > rvm = expr(s, r.p + 1);
        FORIT(it_, rvm) FORIT(it, (it_->second)) if(res[it->p].size() < 2){
          res[it->p].push_back(Result(r.value + " " + it->value + ")", it->p));
        }
      }else if(isupper(s[r.p + 1])){
        string word;
        while(isupper(s[r.p + 1])) word += s[++r.p];
        if(res[r.p + 1].size() < 2){
          res[r.p + 1].push_back(Result(r.value + " " + word + ")", r.p + 1));
        }
      }else{
        assert(false);
      }
    }else {
      assert(r.p == (int)s.size());
    }
  }
  used[P] = true;
  return res;
}
int main(){
  int N;
  cin >> N;
  cin.ignore();
  while(N--){
    string s;
    REP(i, 1000) memo[i].clear();
    REP(i, 1000) used[i] = false;
    getline(cin, s);
    replace(s, "a list of", "[");
    replace(s, "and", "&");
    replace(s, " ", "");
    map<int, vector<Result> > rvm = expr(s, 0);
    if(rvm[s.size()].size() == 1){
      cout << rvm[s.size()][0].value << endl;
    }else if(rvm[s.size()].size() > 1){
      cout << "AMBIGUOUS" << endl;
    }else{
      cout << "NULL"<<endl;
    }
  }
  return 0;
}
accuracy: 1
time_ms: 240
memory_kb: 2628
final_rank: 1

code_snippet: #include <iostream>
#include <sstream>
#include <string>
#include <algorithm>
#include <vector>
#include <stack>
#include <queue>
#include <set>
#include <map>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <cassert>

using namespace std;

#define FOR(i,k,n) for(int i=(k); i<(int)(n); ++i)
#define REP(i,n) FOR(i,0,n)
#define FORIT(i,c) for(__typeof((c).begin())i=(c).begin();i!=(c).end();++i)

template<class T> void debug(T begin, T end){ for(T i = begin; i != end; ++i) cerr<<*i<<" "; cerr<<endl; }
inline bool valid(int x, int y, int W, int H){ return (x >= 0 && y >= 0 && x < W && y < H); }

typedef long long ll;
const int INF = 100000000;
const double EPS = 1e-8;
const int MOD = 1000000007;
int dx[8] = {1, 0, -1, 0, 1, -1, -1, 1};
int dy[8] = {0, 1, 0, -1, 1, 1, -1, -1};
void replace(string& s, const string& from, const string& to){
  string::size_type pos = s.find(from);
  while(pos != string::npos){
    s.replace(pos, from.size(), to);
    pos = s.find(from, pos + to.size());
  }
}
struct Result{
  string value;
  int p;
  Result(string s, int p) : value(s), p(p){}
};
map<int, vector<Result> > memo[1000];
bool used[1000];
map<int, vector<Result> > expr(const string& s, int p){
  int P = p; 
  assert(P >= 0 && P < 1000);
  if(used[P]) return memo[P];
  //printf("expr %d %s\n", p, (s.substr(0, p) + "*" + s.substr(p + 1)).c_str());
  assert(s[p] == '[');
  p++;
  queue<Result> que;
  map<int, vector<Result> >& res = memo[P];
  vector<int> cnt(s.size() + 1);
  if(isupper(s[p])){
    string word;
    while(isupper(s[p])) word += s[p++];
    Result r("(" + word, p);
    que.push(r);
    //printf("\t(expr %d) push_back R(%s, %d)\n", P, (r.value + ")").c_str(), r.p);
    res[r.p].push_back(Result(r.value + ")", r.p));
  }else{
    //printf("\t(expr %d) call1 expr %d\n", P, p);
    map<int, vector<Result> > rvm = expr(s, p);
    FORIT(it_, rvm)FORIT(it, it_->second){
      que.push(Result("(" + it->value, it->p));
      //printf("\t(expr %d) push_back R(%s, %d)\n", P, ("(" + it->value + ")").c_str(), it->p);
      res[it->p].push_back(Result("(" + it->value + ")", it->p));
    }
  }
  while(!que.empty()){
    Result r = que.front(); que.pop();
    //printf("\tque R(%s, %d)\n", r.value.c_str(), r.p);
    if(s[r.p] == ','){
      if(s[r.p + 1] == '['){
        //printf("\t(expr %d) call2 expr %d\n", P, r.p + 1);
        map<int, vector<Result> > rvm = expr(s, r.p + 1);
        FORIT(it_, rvm) FORIT(it, it_->second) if(cnt[it->p] < 2){
          cnt[it->p]++;
          que.push(Result(r.value + " " + it->value, it->p));
          //res[it->p].push_back(Result(r.value + " " + it->value + ")", it->p));
        }
      }else if(isupper(s[r.p + 1])){
        string word;
        while(isupper(s[r.p + 1])) word += s[++r.p];
        if(cnt[r.p + 1] < 2){
          cnt[r.p + 1]++;
          que.push(Result(r.value + " " + word, r.p + 1));
          //res[r.p + 1].push_back(Result(r.value + " " + word + ")", r.p + 1));
        }
      }else{
        assert(false);
      }
    }else if(s[r.p] == '&'){
      if(s[r.p + 1] == '['){
        //printf("\tcall3 expr %d\n", r.p + 1);
        map<int, vector<Result> > rvm = expr(s, r.p + 1);
        FORIT(it_, rvm) FORIT(it, (it_->second)) if(res[it->p].size() < 2){
          res[it->p].push_back(Result(r.value + " " + it->value + ")", it->p));
          //printf("\t(expr %d) push_back R(%s, %d)\n", P, ("(" + it->value + ")").c_str(), it->p);
        }
      }else if(isupper(s[r.p + 1])){
        string word;
        while(isupper(s[r.p + 1])) word += s[++r.p];
        if(res[r.p + 1].size() < 2){
          res[r.p + 1].push_back(Result(r.value + " " + word + ")", r.p + 1));
          //printf("\t(expr %d) push_back R(%s, %d)\n", P, (r.value + " " + word + ")").c_str(), r.p + 1);
        }
      }else{
        assert(false);
      }
    }else {
      assert(r.p == (int)s.size());
    }
  }
  used[P] = true;
  //printf("(expr %d) return\n", P);
  return res;
}
int main(){
  int N;
  cin >> N;
  cin.ignore();
  while(N--){
    string s;
    REP(i, 1000) memo[i].clear();
    REP(i, 1000) used[i] = false;
    getline(cin, s);
    //cout << "#" << s << endl;
    replace(s, "a list of", "[");
    replace(s, "and", "&");
    replace(s, " ", "");
    map<int, vector<Result> > rvm = expr(s, 0);
    if(rvm[s.size()].size() == 1){
      cout << rvm[s.size()][0].value << endl;
    }else if(rvm[s.size()].size() > 1){
      cout << "AMBIGUOUS" << endl;
    }else{
      cout << "NULL"<<endl;
    }
  }
  return 0;
}
accuracy: 1
time_ms: 240
memory_kb: 2628
final_rank: 1