CDTN02-Editorial

Observe that since Ash always completes his journey in minimum total time, he never visits the same city twice. In other words, the string formed the ash is a path.

Suppose the ash starts his journey from cell (0,j) , visits every cell to its left and comes to cell (0,0) , then visits cell (1,0) and every cell to its right to cell (1,j). Now there are two possible options for the Ash if he wishes to visit each cell.

1.He can move right to cell (1,n-1), visiting all cells in between, and then go up to cell (0,n-1). From there visit all cells to its left until it reaches cell (0,j+1) thereby completing the tour.

2.Otherwise he can move to cell (1,j+1) followed by a move to cell (0,j+1) . In this case there are again two possible options for Ash. Move from cell (0,j+1) to cell (0,j+2) followed by a move to cell (1,j+2) and have two choices again. Or visit all cells to its right , move down and visit all remaining cells to its left.

Note that he can start from cell (1,j) instead of cell (0,j) . Also, he can start from column j, visit every cell to its right, move down/up and visit every cell to its left until it reaches column j again and repeat the same procedure with two choices as elaborated before. So we need to handle these cases as well with a similar strategy as described.

C++ code -
C++
#include <bits/stdc++.h>
#define forn(i, n) for(int i = 0; i < int(n); ++i)

using namespace std;

typedef long long li;
typedef long double ld;

const li MOD = li(1e18) + 31;
const li BASE = li(1e9) + 9;

const int N = 5000 + 5;
int n;
char s[2][N];

li bpw[N];
li hl[2][N], hr[2][N], hz[2][N];

li mul(li a, li b) {
li q = li(ld(a) * b / MOD);
li r = a * b - q * MOD;
while (r < 0)
r += MOD;
while (r >= MOD)
r -= MOD;
return r;
}

li add(li a, li b) {
a += b;
if (a >= MOD)
a -= MOD;
return a;
}

li sub(li a, li b) {
a -= b;
if (a < 0)
a += MOD;
return a;
}

void pchash(string s, li *h) {
h[0] = 0;
forn(i, s.size())
h[i + 1] = add(mul(h[i], BASE), s[i]);
}

li chash(li *h, int l, int len) {
return sub(h[l + len], mul(h[l], bpw[len]));
}

string rev(string s) {
reverse(s.begin(), s.end());
return s;
}

void solve() {
assert(scanf("%d", &n) == 1);
assert(1 <= n && n <= 600);
forn(i, 2) {
assert(scanf("%s", s[i]) == 1);
cerr << n << " " << s[i] << endl;
assert((int) strlen(s[i]) == n);
}
vector

  • all;
    forn(_, 2) {
        pchash(rev(s[0]) + s[1], hl[0]);
        pchash(rev(s[1]) + s[0], hl[1]);
        pchash(s[0] + rev(s[1]), hr[0]);
        pchash(s[1] + rev(s[0]), hr[1]);
    
    
        forn(k, 2) {
            string t;
            forn(i, n)
                forn(j, 2)
                    t.push_back(s[(k ^ i ^ j) & 1][i]);
            pchash(t, hz[k]);
        }
    
        forn(r, 2) {
            forn(c, n) {
                li h = chash(hl[r], n - c - 1, 2 * (c + 1));
                for (int len = 0; c + 1 + len <= n; len++) {
                    int pos = c + 1;
                    li ch = mul(h, bpw[2 * len]);
                    ch = add(ch, chash(hz[(r ^ pos ^ 1) & 1], 2 * pos, 2 * len));
                    pos += len;
                    ch = mul(ch, bpw[2 * (n - pos)]);
                    ch = add(ch, chash(hr[(r ^ 1 ^ len) & 1], pos, 2 * (n - pos)));
                    all.push_back(ch);
                }
            }
        }
    
        forn(i, 2)
            reverse(s[i], s[i] + n);
    }
    
    sort(all.begin(), all.end());
    all.erase(unique(all.begin(), all.end()), all.end());
    printf("%d\n", (int) all.size());
    

    }

    int main() {
    bpw[0] = 1;
    forn(i, N - 1)
    bpw[i + 1] = mul(bpw[i], BASE);

    int T;
    assert(scanf("%d", &T) == 1);
    assert(1 <= T && T <= 15);
    forn(i, T)
        solve();
    return 0;
    

    }