Checker for Array Shuffling (Codeforces 1672F2)
Tags: Others, graphs

oolimry has an array $$$a$$$ of length $$$n$$$ which he really likes. Today, you have changed his array to $$$b$$$, a permutation of $$$a$$$, to make him sad.Because oolimry is only a duck, he can only perform the following operation to restore his array:   Choose two integers $$$i,j$$$ such that $$$1 \leq i,j \leq n$$$.  Swap $$$b_i$$$ and $$$b_j$$$. The sadness of the array $$$b$$$ is the minimum number of operations needed to transform $$$b$$$ into $$$a$$$.Given the arrays $$$a$$$ and $$$b$$$, where $$$b$$$ is a permutation of $$$a$$$, determine if $$$b$$$ has the maximum sadness over all permutations of $$$a$$$.

Input: Each test contains multiple test cases. The first line contains a single integer $$$t$$$ ($$$1 \leq t \leq 10^4$$$)  — the number of test cases. The description of the test cases follows.The first line of each test case contains a single integer $$$n$$$ ($$$1 \leq n \leq 2 \cdot 10^5$$$)  — the length of the array.The second line of each test case contains $$$n$$$ integers $$$a_1, a_2, \ldots, a_n$$$ ($$$1 \leq a_i \leq n$$$)  — the elements of the array $$$a$$$.The third line of each test case contains $$$n$$$ integers $$$b_1, b_2, \ldots, b_n$$$ ($$$1 \leq b_i \leq n$$$)  — the elements of the array $$$b$$$.It is guaranteed that $$$b$$$ is a permutation of $$$a$$$.It is guaranteed that the sum of $$$n$$$ over all test cases does not exceed $$$2 \cdot 10^5$$$.

Output: For each test case, print "AC" (without quotes) if $$$b$$$ has the maximum sadness over all permutations of $$$a$$$, and "WA" (without quotes) otherwise.

Note: In the first test case, the array $$$[1,2]$$$ has sadness $$$1$$$. We can transform $$$[1,2]$$$ into $$$[2,1]$$$ using one operation with $$$(i,j)=(1,2)$$$.In the second test case, the array $$$[3,3,2,1]$$$ has sadness $$$2$$$. We can transform $$$[3,3,2,1]$$$ into $$$[1,2,3,3]$$$ with two operations with $$$(i,j)=(1,4)$$$ and $$$(i,j)=(2,3)$$$ respectively.In the third test case, the array $$$[2,1]$$$ has sadness $$$0$$$.In the fourth test case, the array $$$[3,2,3,1]$$$ has sadness $$$1$$$.

Sample Inputs:
4
2
2 1
1 2
4
1 2 3 3
3 3 2 1
2
2 1
2 1
4
1 2 3 3
3 2 3 1

Sample Outputs:
AC
AC
WA
WA

Solution (Python):
from collections import deque

def solve():
    n = int(input())
    arr = list(map(int, input().split()))
    arr1 = list(map(int, input().split()))
    cnt = [0] * (n + 1)
    for a in arr:
        cnt[a] += 1
    x = cnt.index(max(cnt))
    g = [[] for i in range(n + 1)]
    deg = [0] * (n + 1)
    for i in range(n):
        if arr[i] != x and arr1[i] != x:
            g[arr[i]].append(arr1[i])
            deg[arr1[i]] += 1
    ans = 0
    q = deque()
    for i in range(1, n + 1):
        if deg[i] == 0 and i != x:
            q.append(i)
    while q:
        i = q.popleft()
        ans += 1
        for j in g[i]:
            deg[j] -= 1
            if deg[j] == 0:
                q.append(j)
    if ans < n - 1:
        return 'WA'
    return 'AC'
import sys
input = lambda : sys.stdin.readline().rstrip()
t = int(input())
for i in range(t):
    print(solve())

Solution (Python):
import sys
I = lambda : [*map(int, sys.stdin.readline().split())]
import collections
(t,) = I()
for _ in range(t):
    (n,) = I()
    a = I()
    b = I()
    a = [val - 1 for val in a]
    b = [val - 1 for val in b]
    (freq, occ) = collections.Counter(a).most_common(1)[0]
    inds = {}
    bad = False
    for i in range(n):
        if a[i] != b[i]:
            if a[i] in inds:
                inds[a[i]].add(i)
            else:
                inds[a[i]] = {i}
        elif a[i] != freq:
            bad = True
    if bad:
        print('WA')
        continue
    bb = b[:]
    cycles = []
    for i in range(n):
        if a[i] != b[i]:
            cycle = [i]
            curr = i
            while True:
                curr = inds[b[curr]].pop()
                if curr == i:
                    break
                cycle.append(curr)
            cycles.append(cycle)
            for j in cycle:
                b[j] = a[j]
    out = [[] for i in range(n)]
    ins = [0] * n
    for cycle in cycles:
        l = len(cycle)
        for i in range(l):
            if a[cycle[i]] != freq and a[cycle[i - 1]] != freq:
                out[a[cycle[i - 1]]].append(a[cycle[i]])
                ins[a[cycle[i]]] += 1
    q = []
    for i in range(n):
        if ins[i] == 0:
            q.append(i)
    qind = 0
    while qind < len(q):
        v = q[qind]
        for v1 in out[v]:
            ins[v1] -= 1
            if ins[v1] == 0:
                q.append(v1)
        qind += 1
    if sum(ins) > 0:
        print('WA')
    else:
        print('AC')

Solution (Python):
def divisors(M):
    d = []
    i = 1
    while M >= i ** 2:
        if M % i == 0:
            d.append(i)
            if i ** 2 != M:
                d.append(M // i)
        i = i + 1
    return d

def popcount(x):
    x = x - (x >> 1 & 1431655765)
    x = (x & 858993459) + (x >> 2 & 858993459)
    x = x + (x >> 4) & 252645135
    x = x + (x >> 8)
    x = x + (x >> 16)
    return x & 127

def eratosthenes(n):
    res = [0 for i in range(n + 1)]
    prime = set([])
    for i in range(2, n + 1):
        if not res[i]:
            prime.add(i)
            for j in range(1, n // i + 1):
                res[i * j] = 1
    return prime

def factorization(n):
    res = []
    for p in prime:
        if n % p == 0:
            while n % p == 0:
                n //= p
            res.append(p)
    if n != 1:
        res.append(n)
    return res

def euler_phi(n):
    res = n
    for x in range(2, n + 1):
        if x ** 2 > n:
            break
        if n % x == 0:
            res = res // x * (x - 1)
            while n % x == 0:
                n //= x
    if n != 1:
        res = res // n * (n - 1)
    return res

def ind(b, n):
    res = 0
    while n % b == 0:
        res += 1
        n //= b
    return res

def isPrimeMR(n):
    d = n - 1
    d = d // (d & -d)
    L = [2, 3, 5, 7, 11, 13, 17]
    for a in L:
        t = d
        y = pow(a, t, n)
        if y == 1:
            continue
        while y != n - 1:
            y = y * y % n
            if y == 1 or t == n - 1:
                return 0
            t <<= 1
    return 1

def findFactorRho(n):
    from math import gcd
    m = 1 << n.bit_length() // 8
    for c in range(1, 99):
        f = lambda x: (x * x + c) % n
        (y, r, q, g) = (2, 1, 1, 1)
        while g == 1:
            x = y
            for i in range(r):
                y = f(y)
            k = 0
            while k < r and g == 1:
                ys = y
                for i in range(min(m, r - k)):
                    y = f(y)
                    q = q * abs(x - y) % n
                g = gcd(q, n)
                k += m
            r <<= 1
        if g == n:
            g = 1
            while g == 1:
                ys = f(ys)
                g = gcd(abs(x - ys), n)
        if g < n:
            if isPrimeMR(g):
                return g
            elif isPrimeMR(n // g):
                return n // g
            return findFactorRho(g)

def primeFactor(n):
    i = 2
    ret = {}
    rhoFlg = 0
    while i * i <= n:
        k = 0
        while n % i == 0:
            n //= i
            k += 1
        if k:
            ret[i] = k
        i += 1 + i % 2
        if i == 101 and n >= 2 ** 20:
            while n > 1:
                if isPrimeMR(n):
                    (ret[n], n) = (1, 1)
                else:
                    rhoFlg = 1
                    j = findFactorRho(n)
                    k = 0
                    while n % j == 0:
                        n //= j
                        k += 1
                    ret[j] = k
    if n > 1:
        ret[n] = 1
    if rhoFlg:
        ret = {x: ret[x] for x in sorted(ret)}
    return ret

def divisors(n):
    res = [1]
    prime = primeFactor(n)
    for p in prime:
        newres = []
        for d in res:
            for j in range(prime[p] + 1):
                newres.append(d * p ** j)
        res = newres
    res.sort()
    return res

def xorfactorial(num):
    if num == 0:
        return 0
    elif num == 1:
        return 1
    elif num == 2:
        return 3
    elif num == 3:
        return 0
    else:
        x = baseorder(num)
        return 2 ** x * ((num - 2 ** x + 1) % 2) + function(num - 2 ** x)

def xorconv(n, X, Y):
    if n == 0:
        res = [X[0] * Y[0] % mod]
        return res
    x = [X[i] + X[i + 2 ** (n - 1)] for i in range(2 ** (n - 1))]
    y = [Y[i] + Y[i + 2 ** (n - 1)] for i in range(2 ** (n - 1))]
    z = [X[i] - X[i + 2 ** (n - 1)] for i in range(2 ** (n - 1))]
    w = [Y[i] - Y[i + 2 ** (n - 1)] for i in range(2 ** (n - 1))]
    res1 = xorconv(n - 1, x, y)
    res2 = xorconv(n - 1, z, w)
    former = [(res1[i] + res2[i]) * inv for i in range(2 ** (n - 1))]
    latter = [(res1[i] - res2[i]) * inv for i in range(2 ** (n - 1))]
    former = list(map(lambda x: x % mod, former))
    latter = list(map(lambda x: x % mod, latter))
    return former + latter

def merge_sort(A, B):
    (pos_A, pos_B) = (0, 0)
    (n, m) = (len(A), len(B))
    res = []
    while pos_A < n and pos_B < m:
        (a, b) = (A[pos_A], B[pos_B])
        if a < b:
            res.append(a)
            pos_A += 1
        else:
            res.append(b)
            pos_B += 1
    res += A[pos_A:]
    res += B[pos_B:]
    return res

class UnionFindVerSize:

    def __init__(self, N):
        self._parent = [n for n in range(0, N)]
        self._size = [1] * N
        self.group = N

    def find_root(self, x):
        if self._parent[x] == x:
            return x
        self._parent[x] = self.find_root(self._parent[x])
        stack = [x]
        while self._parent[stack[-1]] != stack[-1]:
            stack.append(self._parent[stack[-1]])
        for v in stack:
            self._parent[v] = stack[-1]
        return self._parent[x]

    def unite(self, x, y):
        gx = self.find_root(x)
        gy = self.find_root(y)
        if gx == gy:
            return
        self.group -= 1
        if self._size[gx] < self._size[gy]:
            self._parent[gx] = gy
            self._size[gy] += self._size[gx]
        else:
            self._parent[gy] = gx
            self._size[gx] += self._size[gy]

    def get_size(self, x):
        return self._size[self.find_root(x)]

    def is_same_group(self, x, y):
        return self.find_root(x) == self.find_root(y)

class WeightedUnionFind:

    def __init__(self, N):
        self.parent = [i for i in range(N)]
        self.size = [1 for i in range(N)]
        self.val = [0 for i in range(N)]
        self.flag = True
        self.edge = [[] for i in range(N)]

    def dfs(self, v, pv):
        stack = [(v, pv)]
        new_parent = self.parent[pv]
        while stack:
            (v, pv) = stack.pop()
            self.parent[v] = new_parent
            for (nv, w) in self.edge[v]:
                if nv != pv:
                    self.val[nv] = self.val[v] + w
                    stack.append((nv, v))

    def unite(self, x, y, w):
        if not self.flag:
            return
        if self.parent[x] == self.parent[y]:
            self.flag = self.val[x] - self.val[y] == w
            return
        if self.size[self.parent[x]] > self.size[self.parent[y]]:
            self.edge[x].append((y, -w))
            self.edge[y].append((x, w))
            self.size[x] += self.size[y]
            self.val[y] = self.val[x] - w
            self.dfs(y, x)
        else:
            self.edge[x].append((y, -w))
            self.edge[y].append((x, w))
            self.size[y] += self.size[x]
            self.val[x] = self.val[y] + w
            self.dfs(x, y)

class Dijkstra:

    class Edge:

        def __init__(self, _to, _cost):
            self.to = _to
            self.cost = _cost

    def __init__(self, V):
        self.G = [[] for i in range(V)]
        self._E = 0
        self._V = V

    @property
    def E(self):
        return self._E

    @property
    def V(self):
        return self._V

    def add_edge(self, _from, _to, _cost):
        self.G[_from].append(self.Edge(_to, _cost))
        self._E += 1

    def shortest_path(self, s):
        import heapq
        que = []
        d = [10 ** 15] * self.V
        d[s] = 0
        heapq.heappush(que, (0, s))
        while len(que) != 0:
            (cost, v) = heapq.heappop(que)
            if d[v] < cost:
                continue
            for i in range(len(self.G[v])):
                e = self.G[v][i]
                if d[e.to] > d[v] + e.cost:
                    d[e.to] = d[v] + e.cost
                    heapq.heappush(que, (d[e.to], e.to))
        return d

def Z_algorithm(s):
    N = len(s)
    Z_alg = [0] * N
    Z_alg[0] = N
    i = 1
    j = 0
    while i < N:
        while i + j < N and s[j] == s[i + j]:
            j += 1
        Z_alg[i] = j
        if j == 0:
            i += 1
            continue
        k = 1
        while i + k < N and k + Z_alg[k] < j:
            Z_alg[i + k] = Z_alg[k]
            k += 1
        i += k
        j -= k
    return Z_alg

class BIT:

    def __init__(self, n, mod=0):
        self.BIT = [0] * (n + 1)
        self.num = n
        self.mod = mod

    def query(self, idx):
        res_sum = 0
        mod = self.mod
        while idx > 0:
            res_sum += self.BIT[idx]
            if mod:
                res_sum %= mod
            idx -= idx & -idx
        return res_sum

    def update(self, idx, x):
        mod = self.mod
        while idx <= self.num:
            self.BIT[idx] += x
            if mod:
                self.BIT[idx] %= mod
            idx += idx & -idx
        return

class dancinglink:

    def __init__(self, n, debug=False):
        self.n = n
        self.debug = debug
        self._left = [i - 1 for i in range(n)]
        self._right = [i + 1 for i in range(n)]
        self.exist = [True for i in range(n)]

    def pop(self, k):
        if self.debug:
            assert self.exist[k]
        L = self._left[k]
        R = self._right[k]
        if L != -1:
            if R != self.n:
                (self._right[L], self._left[R]) = (R, L)
            else:
                self._right[L] = self.n
        elif R != self.n:
            self._left[R] = -1
        self.exist[k] = False

    def left(self, idx, k=1):
        if self.debug:
            assert self.exist[idx]
        res = idx
        while k:
            res = self._left[res]
            if res == -1:
                break
            k -= 1
        return res

    def right(self, idx, k=1):
        if self.debug:
            assert self.exist[idx]
        res = idx
        while k:
            res = self._right[res]
            if res == self.n:
                break
            k -= 1
        return res

class SparseTable:

    def __init__(self, A, merge_func, ide_ele):
        N = len(A)
        self.merge_func = merge_func
        self.lg = [0] * (N + 1)
        for i in range(2, N + 1):
            self.lg[i] = self.lg[i >> 1] + 1
        self.pow_2 = [pow(2, i) for i in range(20)]
        self.table = [None] * (self.lg[N] + 1)
        st0 = self.table[0] = [a for a in A]
        b = 1
        for i in range(self.lg[N]):
            st0 = self.table[i + 1] = [self.merge_func(u, v) for (u, v) in zip(st0, st0[b:])]
            b <<= 1

    def query(self, s, t):
        b = t - s + 1
        m = self.lg[b]
        return self.merge_func(self.table[m][s], self.table[m][t - self.pow_2[m] + 1])

class BinaryTrie:

    class node:

        def __init__(self, val):
            self.left = None
            self.right = None
            self.max = val

    def __init__(self):
        self.root = self.node(-10 ** 15)

    def append(self, key, val):
        pos = self.root
        for i in range(29, -1, -1):
            pos.max = max(pos.max, val)
            if key >> i & 1:
                if pos.right is None:
                    pos.right = self.node(val)
                    pos = pos.right
                else:
                    pos = pos.right
            elif pos.left is None:
                pos.left = self.node(val)
                pos = pos.left
            else:
                pos = pos.left
        pos.max = max(pos.max, val)

    def search(self, M, xor):
        res = -10 ** 15
        pos = self.root
        for i in range(29, -1, -1):
            if pos is None:
                break
            if M >> i & 1:
                if xor >> i & 1:
                    if pos.right:
                        res = max(res, pos.right.max)
                    pos = pos.left
                else:
                    if pos.left:
                        res = max(res, pos.left.max)
                    pos = pos.right
            elif xor >> i & 1:
                pos = pos.right
            else:
                pos = pos.left
        if pos:
            res = max(res, pos.max)
        return res

def solveequation(edge, ans, n, m):

    def dfs(v):
        used[v] = True
        r = ans[v]
        for (to, dire, id) in edge[v]:
            if used[to]:
                continue
            y = dfs(to)
            if dire == -1:
                x[id] = y
            else:
                x[id] = -y
            r += y
        return r
    x = [0] * m
    used = [False] * n
    for v in range(n):
        if used[v]:
            continue
        y = dfs(v)
        if y != 0:
            return False
    return x

class slope_trick:

    def __init__(self):
        self.L = [10 ** 17]
        self.R = [10 ** 17]
        self.min_f = 0
        self.x_left = 0
        self.x_right = 0

    def add_right(self, a):
        a -= self.x_left
        l0 = -self.L[0]
        self.min_f = self.min_f + max(0, l0 - a)
        if l0 <= a:
            a += self.x_left
            a -= self.x_right
            heappush(self.R, a)
        else:
            heappush(self.L, -a)
            a = -heappop(self.L)
            a += self.x_left
            a -= self.x_right
            heappush(self.R, a)

    def add_left(self, a):
        a -= self.x_right
        r0 = self.R[0]
        self.min_f = self.min_f + max(0, a - r0)
        if a <= r0:
            a += self.x_right
            a -= self.x_left
            heappush(self.L, -a)
        else:
            heappush(self.R, a)
            a = heappop(self.R)
            a += self.x_right
            a -= self.x_left
            heappush(self.L, -a)

    def add_abs(self, a):
        self.add_left(a)
        self.add_right(a)

    def change_min_slide(self, a, b):
        self.x_left += a
        self.x_right += b

    def get_val(self, x):
        L = [-l + self.x_left for l in self.L]
        L.sort()
        R = [r + self.x_right for r in self.R]
        R.sort()
        res = self.min_f
        if 0 < L[-1]:
            L = L[::-1]
            n = len(L)
            for i in range(n):
                c0 = L[i]
                c1 = L[i + 1]
                if c1 <= x <= c0:
                    res += (i + 1) * (c0 - x)
                    break
                else:
                    res += (i + 1) * (c0 - c1)
            return res
        elif L[-1] <= x <= R[0]:
            return res
        else:
            n = len(R)
            for i in range(n):
                c0 = R[i]
                c1 = R[i + 1]
                if c0 <= x <= c1:
                    res += (i + 1) * (x - c0)
                    break
                else:
                    res += (i + 1) * (c1 - c0)
            return res

class SegmentTree:

    def __init__(self, init_val, segfunc, ide_ele):
        n = len(init_val)
        self.segfunc = segfunc
        self.ide_ele = ide_ele
        self.num = 1 << (n - 1).bit_length()
        self.tree = [ide_ele] * 2 * self.num
        self.size = n
        for i in range(n):
            self.tree[self.num + i] = init_val[i]
        for i in range(self.num - 1, 0, -1):
            self.tree[i] = self.segfunc(self.tree[2 * i], self.tree[2 * i + 1])

    def update(self, k, x):
        k += self.num
        self.tree[k] = x
        while k > 1:
            k >>= 1
            self.tree[k] = self.segfunc(self.tree[2 * k], self.tree[2 * k + 1])

    def query(self, l, r):
        if r == self.size:
            r = self.num
        res = self.ide_ele
        l += self.num
        r += self.num
        right = []
        while l < r:
            if l & 1:
                res = self.segfunc(res, self.tree[l])
                l += 1
            if r & 1:
                right.append(self.tree[r - 1])
            l >>= 1
            r >>= 1
        for e in right[::-1]:
            res = self.segfunc(res, e)
        return res

    def bisect_l(self, l, r, x):
        l += self.num
        r += self.num
        Lmin = -1
        Rmin = -1
        while l < r:
            if l & 1:
                if self.tree[l] <= x and Lmin == -1:
                    Lmin = l
                l += 1
            if r & 1:
                if self.tree[r - 1] <= x:
                    Rmin = r - 1
            l >>= 1
            r >>= 1
        if Lmin != -1:
            pos = Lmin
            while pos < self.num:
                if self.tree[2 * pos] <= x:
                    pos = 2 * pos
                else:
                    pos = 2 * pos + 1
            return pos - self.num
        elif Rmin != -1:
            pos = Rmin
            while pos < self.num:
                if self.tree[2 * pos] <= x:
                    pos = 2 * pos
                else:
                    pos = 2 * pos + 1
            return pos - self.num
        else:
            return -1
import sys, random, bisect
from collections import deque, defaultdict
from heapq import heapify, heappop, heappush
from itertools import permutations
from math import gcd, log
input = lambda : sys.stdin.buffer.readline()
mi = lambda : map(int, input().split())
li = lambda : list(mi())
for _ in range(int(input())):
    n = int(input())
    A = li()
    B = li()
    A = [a - 1 for a in A]
    B = [b - 1 for b in B]
    cnt = [0] * n
    for a in A:
        cnt[a] += 1
    M = max(cnt)
    bye = cnt.index(M)
    edge = [[] for v in range(n)]
    deg = [0] * n
    for i in range(n):
        if A[i] != bye and B[i] != bye:
            edge[A[i]].append(B[i])
            deg[B[i]] += 1
    deq = deque([v for v in range(n) if deg[v] == 0])
    while deq:
        v = deq.popleft()
        for nv in edge[v]:
            deg[nv] -= 1
            if deg[nv] == 0:
                deq.append(nv)
    if sum(deg) > 0:
        print('WA')
    else:
        print('AC')