import std.conv, std.functional, std.range, std.stdio, std.string; import std.algorithm, std.array, std.bigint, std.bitmanip, std.complex, std.container, std.math, std.mathspecial, std.numeric, std.regex, std.typecons; import core.bitop; class EOFException : Throwable { this() { super("EOF"); } } string[] tokens; string readToken() { for (; tokens.empty; ) { if (stdin.eof) { throw new EOFException; } tokens = readln.split; } auto token = tokens.front; tokens.popFront; return token; } int readInt() { return readToken.to!int; } long readLong() { return readToken.to!long; } real readReal() { return readToken.to!real; } bool chmin(T)(ref T t, in T f) { if (t > f) { t = f; return true; } else { return false; } } bool chmax(T)(ref T t, in T f) { if (t < f) { t = f; return true; } else { return false; } } int binarySearch(alias pred, T)(in T[] as) { int lo = -1, hi = cast(int)(as.length); for (; lo + 1 < hi; ) { const mid = (lo + hi) >> 1; (unaryFun!pred(as[mid]) ? hi : lo) = mid; } return hi; } int lowerBound(T)(in T[] as, T val) { return as.binarySearch!(a => (a >= val)); } int upperBound(T)(in T[] as, T val) { return as.binarySearch!(a => (a > val)); } int lis(const(int[]) as) { int[] seq; foreach (a; as) { const pos = seq.lowerBound(a); if (pos == seq.length) { seq ~= a; } else { seq[pos] = a; } } return cast(int)(seq.length); } void judge(const(int) N, const(int) A, const(int) B, const(string) S, const(int[]) xs, const(int[]) ys) { const msg = format("FAIL %s %s %s %s: %s %s", N, A, B, S, xs, ys); assert(xs.length == N, msg); assert(ys.length == N, msg); auto freq = new int[2 * N]; foreach (i; 0 .. N) { assert(0 <= xs[i], msg); assert(xs[i] < 2 * N, msg); assert(0 <= ys[i], msg); assert(ys[i] < 2 * N, msg); ++freq[xs[i]]; ++freq[ys[i]]; } assert(freq.all!"a == 1"); foreach (i; 0 .. N) { final switch (S[i]) { case 'a': assert(xs[i] > ys[i], msg); break; case 'b': assert(xs[i] < ys[i], msg); break; } } assert(lis(xs) == A, msg); assert(lis(ys) == B, msg); } // (left non-C) < (right C) int[] sub(const(int) N, const(int) A, const(string) S, const(char) C) { assert(2 <= A); assert(A <= N); auto tail = new bool[N + 1]; { bool hasC; foreach_reverse (i; 0 .. N) { tail[i] = tail[i + 1]; if (S[i] == C) { hasC = true; } else { if (hasC) { tail[i] = true; } } } } foreach (k; 0 .. N) { if (k + (tail[k] ? 2 : 1) == A) { auto ps = new int[N]; ps[] = -1; int val = 0; foreach (i; 0 .. k) { ps[i] = val++; } foreach_reverse (i; k .. N) if (S[i] != C) { ps[i] = val++; } foreach_reverse (i; k .. N) if (S[i] == C) { ps[i] = val++; } return ps; } } assert(false); } alias Result = Tuple!(int[], "xs", int[], "ys"); Result entangle(const(int) N, const(string) S, const(int[]) ps, const(int[]) qs) { debug { // writeln("[entangle] ", N, " ", S, " ", ps, " ", qs); } auto posP = new int[N]; auto posQ = new int[N]; posP[] = -1; posQ[] = -1; foreach (i; 0 .. N) { posP[ps[i]] = i; posQ[qs[i]] = i; } auto xs = new int[N]; auto ys = new int[N]; xs[] = -1; ys[] = -1; int val; for (int j, k; ; ++j) { for (; k < N; ++k) { const i = posQ[k]; if (~xs[i]) { if (S[i] == 'a') { assert(false); } else { ys[i] = val++; } } else { if (S[i] == 'a') { ys[i] = val++; } else { break; } } } if (j == N) break; xs[posP[j]] = val++; } return Result(xs, ys); } Result solve(const(int) N, const(int) A, const(int) B, const(string) S) { debug { writeln("[solve] ", N, " ", A, " ", B, " ", S); } int[] xs, ys; if (A == 1) { if (B == 1) { auto ps = iota(N).array; ps.reverse; auto res = entangle(N, S, ps, ps); xs = res.xs; ys = res.ys; } else { // (left b) > (right a) ==> IS: a...ab...b auto sumA = new int[N + 1]; foreach (i; 0 .. N) { sumA[i + 1] = sumA[i] + ((S[i] == 'a') ? 1 : 0); } // discard [0, pre) bool check(int pre) { foreach (k; pre .. N + 1) { const l = sumA[k] - sumA[pre]; const r = (N - k) - (sumA[N] - sumA[k]); if (B <= l + r) { return true; } } return false; } if (check(0)) { int lo = 0, hi = N + 1; for (; lo + 1 < hi; ) { const mid = (lo + hi) / 2; (check(mid) ? lo : hi) = mid; } const pre = lo; foreach (k; pre .. N + 1) { const l = sumA[k] - sumA[pre]; const r = (N - k) - (sumA[N] - sumA[k]); if (B == l + r) { auto ps = iota(N).array; ps.reverse; auto qs = new int[N]; qs[] = -1; int val; foreach_reverse (i; k .. N) if (S[i] == 'a') qs[i] = val++; foreach (i; pre .. N) if ((i < k) == (S[i] == 'a')) qs[i] = val++; foreach_reverse (i; pre .. k) if (S[i] == 'b') qs[i] = val++; foreach_reverse (i; 0 .. pre) qs[i] = val++; auto res = entangle(N, S, ps, qs); xs = res.xs; ys = res.ys; break; } } } } } else if (B == 1) { auto res = solve(N, B, A, S.map!(c => cast(char)('a' ^ 'b' ^ c)).array); xs = res.ys; ys = res.xs; } else { const ps = sub(N, A, S, 'a'); const qs = sub(N, B, S, 'b'); auto res = entangle(N, S, ps, qs); xs = res.xs; ys = res.ys; } return Result(xs, ys); } void main() { /* debug { foreach (n; 1 .. 5 + 1) { auto can = new char[][][](1 << n, n + 1, n + 1); foreach (h; 0 .. 1 << n) foreach (a; 0 .. n + 1) { can[h][a][] = '0'; } auto perm = iota(2 * n).array; do { int h; foreach (i; 0 .. n) { if (perm[i] < perm[n + i]) { h |= 1 << i; } } const a = lis(perm[0 .. n]); const b = lis(perm[n .. 2 * n]); can[h][a][b] = '1'; } while (perm.nextPermutation); foreach (h; 0 .. 1 << n) { const string pat = iota(n).map!(i => "ab"[h >> i & 1]).array; writeln(pat, " ", can[h]); } stdout.flush; foreach (h; 0 .. 1 << n) { const string pat = iota(n).map!(i => "ab"[h >> i & 1]).array; foreach (a; 1 .. n + 1) foreach (b; 1 .. n + 1) { const res = solve(n, a, b, pat); if (can[h][a][b] == '1') { judge(n, a, b, pat, res.xs, res.ys); } else { assert(!res.xs); } } } writeln("DONE n = ", n); stdout.flush; } return; } //*/ try { for (; ; ) { const numCases = readInt; foreach (caseId; 0 .. numCases) { const N = readInt; const A = readInt; const B = readInt; const S = readToken; const ans = solve(N, A, B, S); if (ans.xs) { writeln("Yes"); foreach (i; 0 .. N) { if (i) write(" "); write(ans.xs[i] + 1); } writeln; foreach (i; 0 .. N) { if (i) write(" "); write(ans.ys[i] + 1); } writeln; debug { writeln(N, " ", A, " ", B, " ", S, ": ", ans.xs, " ", ans.ys); stdout.flush; judge(N, A, B, S, ans.xs, ans.ys); } } else { writeln("No"); } } } } catch (EOFException e) { } }