Chaotic Merge (Codeforces 1499E)
Tags: Math, strings

You are given two strings $$$x$$$ and $$$y$$$, both consist only of lowercase Latin letters. Let $$$|s|$$$ be the length of string $$$s$$$.Let's call a sequence $$$a$$$ a merging sequence if it consists of exactly $$$|x|$$$ zeros and exactly $$$|y|$$$ ones in some order.A merge $$$z$$$ is produced from a sequence $$$a$$$ by the following rules:   if $$$a_i=0$$$, then remove a letter from the beginning of $$$x$$$ and append it to the end of $$$z$$$;  if $$$a_i=1$$$, then remove a letter from the beginning of $$$y$$$ and append it to the end of $$$z$$$. Two merging sequences $$$a$$$ and $$$b$$$ are different if there is some position $$$i$$$ such that $$$a_i \neq b_i$$$.Let's call a string $$$z$$$ chaotic if for all $$$i$$$ from $$$2$$$ to $$$|z|$$$ $$$z_{i-1} \neq z_i$$$.Let $$$s[l,r]$$$ for some $$$1 \le l \le r \le |s|$$$ be a substring of consecutive letters of $$$s$$$, starting from position $$$l$$$ and ending at position $$$r$$$ inclusive.Let $$$f(l_1, r_1, l_2, r_2)$$$ be the number of different merging sequences of $$$x[l_1,r_1]$$$ and $$$y[l_2,r_2]$$$ that produce chaotic merges. Note that only non-empty substrings of $$$x$$$ and $$$y$$$ are considered.Calculate $$$\sum \limits_{1 \le l_1 \le r_1 \le |x| \\ 1 \le l_2 \le r_2 \le |y|} f(l_1, r_1, l_2, r_2)$$$. Output the answer modulo $$$998\,244\,353$$$.

Input: The first line contains a string $$$x$$$ ($$$1 \le |x| \le 1000$$$).The second line contains a string $$$y$$$ ($$$1 \le |y| \le 1000$$$).Both strings consist only of lowercase Latin letters.

Output: Print a single integer — the sum of $$$f(l_1, r_1, l_2, r_2)$$$ over $$$1 \le l_1 \le r_1 \le |x|$$$ and $$$1 \le l_2 \le r_2 \le |y|$$$ modulo $$$998\,244\,353$$$.

Note: In the first example there are:   $$$6$$$ pairs of substrings "a" and "b", each with valid merging sequences "01" and "10";  $$$3$$$ pairs of substrings "a" and "bb", each with a valid merging sequence "101";  $$$4$$$ pairs of substrings "aa" and "b", each with a valid merging sequence "010";  $$$2$$$ pairs of substrings "aa" and "bb", each with valid merging sequences "0101" and "1010";  $$$2$$$ pairs of substrings "aaa" and "b", each with no valid merging sequences;  $$$1$$$ pair of substrings "aaa" and "bb" with a valid merging sequence "01010"; Thus, the answer is $$$6 \cdot 2 + 3 \cdot 1 + 4 \cdot 1 + 2 \cdot 2 + 2 \cdot 0 + 1 \cdot 1 = 24$$$.

Sample Inputs:
aaa
bb

code
forces

aaaaa
aaa

justamassivetesttocheck
howwellyouhandlemodulooperations

Sample Outputs:
24

1574

0

667387032

Solution (Python):
import sys, os, io
input = io.BytesIO(os.read(0, os.fstat(0).st_size)).readline
x = [0] + list(input().rstrip())
y = [0] + list(input().rstrip())
(n, m) = (len(x) - 1, len(y) - 1)
dpx = [[0] * (m + 1) for _ in range(n + 1)]
dpy = [[0] * (m + 1) for _ in range(n + 1)]
mod = 998244353
ans = 0
for i in range(n + 1):
    xi = x[i]
    for j in range(m + 1):
        yj = y[j]
        if not max(i, j):
            continue
        if i:
            dpx[i][j] += 1
        if j:
            dpy[i][j] += 1
        dpx0 = dpx[i][j]
        dpy0 = dpy[i][j]
        ans += dpx0
        ans %= mod
        ans += dpy0
        ans %= mod
        if i < n and x[i + 1] ^ xi:
            dpx[i + 1][j] += dpx0
            dpx[i + 1][j] %= mod
        if i < n and x[i + 1] ^ yj:
            dpx[i + 1][j] += dpy0
            dpx[i + 1][j] %= mod
        if j < m and y[j + 1] ^ xi:
            dpy[i][j + 1] += dpx0
            dpy[i][j + 1] %= mod
        if j < m and y[j + 1] ^ yj:
            dpy[i][j + 1] += dpy0
            dpy[i][j + 1] %= mod
s = 0
c = 0
for i in range(n):
    if x[i] ^ x[i + 1]:
        c += 1
    else:
        c = 1
    s += c
ans -= s * (m + 1)
ans %= mod
s = 0
c = 0
for i in range(m):
    if y[i] ^ y[i + 1]:
        c += 1
    else:
        c = 1
    s += c
ans -= s * (n + 1)
ans %= mod
print(ans)

Solution (Python):
mod = 998244353
eps = 10 ** (-9)

def main():
    import sys
    input = sys.stdin.readline
    S = input().rstrip('\n')
    T = input().rstrip('\n')
    NS = len(S)
    NT = len(T)
    dp_S = [[0] * (NT + 1) for _ in range(NS + 1)]
    dp_T = [[0] * (NT + 1) for _ in range(NS + 1)]
    for i in range(1, NS + 1):
        dp_S[i][0] = 1
    for j in range(1, NT + 1):
        dp_T[0][j] = 1
    for i in range(NS + 1):
        for j in range(NT + 1):
            if i == j == 0:
                continue
            elif i == 0:
                if S[0] != T[j - 1]:
                    dp_S[1][j] = (dp_S[1][j] + dp_T[0][j]) % mod
                if j + 1 <= NT:
                    if T[j - 1] != T[j]:
                        dp_T[0][j + 1] = (dp_T[0][j + 1] + dp_T[0][j]) % mod
            elif j == 0:
                if T[0] != S[i - 1]:
                    dp_T[i][1] = (dp_T[i][1] + dp_S[i][0]) % mod
                if i + 1 <= NS:
                    if S[i - 1] != S[i]:
                        dp_S[i + 1][0] = (dp_S[i + 1][0] + dp_S[i][0]) % mod
            else:
                if i + 1 <= NS:
                    if S[i - 1] != S[i]:
                        dp_S[i + 1][j] = (dp_S[i + 1][j] + dp_S[i][j]) % mod
                    if T[j - 1] != S[i]:
                        dp_S[i + 1][j] = (dp_S[i + 1][j] + dp_T[i][j] + dp_T[0][j]) % mod
                if j + 1 <= NT:
                    if T[j - 1] != T[j]:
                        dp_T[i][j + 1] = (dp_T[i][j + 1] + dp_T[i][j]) % mod
                    if S[i - 1] != T[j]:
                        dp_T[i][j + 1] = (dp_T[i][j + 1] + dp_S[i][j] + dp_S[i][0]) % mod
    ans = 0
    for i in range(1, NS + 1):
        for j in range(1, NT + 1):
            ans = (ans + dp_S[i][j] + dp_T[i][j]) % mod
    print(ans)
if __name__ == '__main__':
    main()

Solution (Python):
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):
        self.BIT = [0] * (n + 1)
        self.num = n

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

    def update(self, idx, x):
        while idx <= self.num:
            self.BIT[idx] += x
            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)
        n = N.bit_length()
        self.table = [[ide_ele for i in range(n)] for i in range(N)]
        self.merge_func = merge_func
        for i in range(N):
            self.table[i][0] = A[i]
        for j in range(1, n):
            for i in range(0, N - 2 ** j + 1):
                f = self.table[i][j - 1]
                s = self.table[i + 2 ** (j - 1)][j - 1]
                self.table[i][j] = self.merge_func(f, s)

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

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):
    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

    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

class Matrix:
    mod = 10 ** 9 + 7

    def set_mod(m):
        Matrix.mod = m

    def __init__(self, L):
        self.row = len(L)
        self.column = len(L[0])
        self._matrix = L
        for i in range(self.row):
            for j in range(self.column):
                self._matrix[i][j] %= Matrix.mod

    def __getitem__(self, item):
        if type(item) == int:
            raise IndexError('you must specific row and column')
        elif len(item) != 2:
            raise IndexError('you must specific row and column')
        (i, j) = item
        return self._matrix[i][j]

    def __setitem__(self, item, val):
        if type(item) == int:
            raise IndexError('you must specific row and column')
        elif len(item) != 2:
            raise IndexError('you must specific row and column')
        (i, j) = item
        self._matrix[i][j] = val

    def __add__(self, other):
        if (self.row, self.column) != (other.row, other.column):
            raise SizeError('sizes of matrixes are different')
        res = [[0 for j in range(self.column)] for i in range(self.row)]
        for i in range(self.row):
            for j in range(self.column):
                res[i][j] = self._matrix[i][j] + other._matrix[i][j]
                res[i][j] %= Matrix.mod
        return Matrix(res)

    def __sub__(self, other):
        if (self.row, self.column) != (other.row, other.column):
            raise SizeError('sizes of matrixes are different')
        res = [[0 for j in range(self.column)] for i in range(self.row)]
        for i in range(self.row):
            for j in range(self.column):
                res[i][j] = self._matrix[i][j] - other._matrix[i][j]
                res[i][j] %= Matrix.mod
        return Matrix(res)

    def __mul__(self, other):
        if type(other) != int:
            if self.column != other.row:
                raise SizeError('sizes of matrixes are different')
            res = [[0 for j in range(other.column)] for i in range(self.row)]
            for i in range(self.row):
                for j in range(other.column):
                    temp = 0
                    for k in range(self.column):
                        temp += self._matrix[i][k] * other._matrix[k][j]
                    res[i][j] = temp % Matrix.mod
            return Matrix(res)
        else:
            n = other
            res = [[n * self._matrix[i][j] % Matrix.mod for j in range(self.column)] for i in range(self.row)]
            return Matrix(res)

    def __pow__(self, m):
        if self.column != self.row:
            raise MatrixPowError('the size of row must be the same as that of column')
        n = self.row
        res = Matrix([[int(i == j) for i in range(n)] for j in range(n)])
        while m:
            if m % 2 == 1:
                res = res * self
            self = self * self
            m //= 2
        return res

    def __str__(self):
        res = []
        for i in range(self.row):
            for j in range(self.column):
                res.append(str(self._matrix[i][j]))
                res.append(' ')
            res.append('\n')
        res = res[:len(res) - 1]
        return ''.join(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
        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:
            self.tree[k >> 1] = self.segfunc(self.tree[k], self.tree[k ^ 1])
            k >>= 1

    def query(self, l, r):
        res = self.ide_ele
        l += self.num
        r += self.num
        while l < r:
            if l & 1:
                res = self.segfunc(res, self.tree[l])
                l += 1
            if r & 1:
                res = self.segfunc(res, self.tree[r - 1])
            l >>= 1
            r >>= 1
        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 log, gcd
input = lambda : sys.stdin.readline().rstrip()
mi = lambda : map(int, input().split())
li = lambda : list(mi())
mod = 998244353
x = input()
n = len(x)
y = input()
m = len(y)
dp_x = [[1 for j in range(m + 1)] for i in range(n + 1)]
dp_y = [[1 for j in range(m + 1)] for i in range(n + 1)]
dp_x[n][m] = 1
dp_y[n][m] = 1
res = 0
for i in range(n, -1, -1):
    for j in range(m, -1, -1):
        if i != n:
            res += dp_x[i + 1][j]
            res %= mod
        if j != m:
            res += dp_y[i][j + 1]
            res %= mod
        if i != 0:
            if i != n and x[i - 1] != x[i]:
                dp_x[i][j] += dp_x[i + 1][j]
                dp_x[i][j] %= mod
            if j != m and x[i - 1] != y[j]:
                dp_x[i][j] += dp_y[i][j + 1]
                dp_x[i][j] %= mod
        if j != 0:
            if i != n and y[j - 1] != x[i]:
                dp_y[i][j] += dp_x[i + 1][j]
                dp_y[i][j] %= mod
            if j != m and y[j - 1] != y[j]:
                dp_y[i][j] += dp_y[i][j + 1]
                dp_y[i][j] %= mod
for i in range(n):
    pre = ''
    L = 0
    for j in range(i, n):
        if x[j] != pre:
            L += 1
            pre = x[j]
        else:
            break
    res -= L * (m + 1)
    res %= mod
for i in range(m):
    pre = ''
    L = 0
    for j in range(i, m):
        if y[j] != pre:
            L += 1
            pre = y[j]
        else:
            break
    res -= L * (n + 1)
    res %= mod
print(res)