Problem: 2050E - Three Strings
Language: python

Solution 1 (runtime: 265 ms):
import sys, random, math, string, itertools
from copy import deepcopy
from collections import defaultdict, Counter, deque
from heapq import heapify, heappush, heappop
from functools import cache
from bisect import bisect_left, bisect_right
from types import GeneratorType
from typing import *

input = lambda: sys.stdin.readline().strip()


def debug(*x, **y):
    if not DEBUG_ENABLED:
        return
    print(*x, (y if y != {} else "\b"), file=sys.stderr)


###############################################################################


def solve_bruteforce(case=None):
    pass


def execute_once():
    pass

def solve(case=None):
    a,b,c = input(),input(),input()

    # @cache
    # def dp(i,j):
    #     ind = i+j 

    #     if ind == len(c):
    #         return 0
        
    #     ch = c[ind]

    #     return min(
    #         (dp(i+1,j) + (1 if a[i] != ch else 0) ) if i < len(a) else math.inf,
    #         (dp(i,j+1) + (1 if b[j] != ch else 0) ) if j < len(b) else math.inf
    #     )

    n,m = len(a),len(b)

    dp = [[math.inf]*(m+1) for _ in range(n+1)]
    dp[-1][-1] = 0

    for i in range(n,-1,-1):
        for j in range(m,-1,-1):
            if i+j == len(c):
                continue

            ch = c[i+j]

            if i < n:
                dp[i][j] = min(dp[i][j], dp[i+1][j] + (1 if a[i] != ch else 0))
            if j < m:
                dp[i][j] = min(dp[i][j], dp[i][j+1] + (1 if b[j] != ch else 0))
    
    # for i in dp:
    #     print(i)

    ans = dp[0][0]
    print(ans)


INPUT_NUMBER_OF_TEST_CASES = 1
SKIP_SOLVE = 0
DEBUG_ENABLED = 1
MOD = 10**9 + 7
BOOLEAN_RETURN = 0
TRUE_MAPPING, FALSE_MAPPING = "YES", "NO"

###############################################################################


class CustomHashMap:
    def __init__(self, map_type=dict, arg=None):
        """
        Custom HashMap for Python's Anti-hash-table test
        :param map_type: type of the map (allowed types: dict, defaultdict, Counter)
        :param arg: argument for the map (should be list if map_type is Counter and function if map_type is defaultdict)
        """
        self.RANDOM = random.randrange(2**62)
        if map_type == Counter:
            self.dict = map_type([self.wrapper(i) for i in arg])
        elif map_type == defaultdict:
            self.dict = map_type(arg)
        else:
            self.dict = map_type()

    def wrapper(self, num):
        return num ^ self.RANDOM

    def __setitem__(self, key, value):
        self.dict[self.wrapper(key)] = value

    def __getitem__(self, key):
        return self.dict[self.wrapper(key)]

    def __contains__(self, key):
        return self.wrapper(key) in self.dict

    def __iter__(self):
        return iter(self.wrapper(i) for i in self.dict)

    def keys(self):
        return [self.wrapper(i) for i in self.dict]

    def values(self):
        return [i for i in self.dict.values()]

    def items(self):
        return [(self.wrapper(i), j) for i, j in self.dict.items()]

    def __repr__(self):
        return repr({self.wrapper(i): j for i, j in self.dict.items()})


def recursion_limit_fix(f):
    """
    recursion limit fix decorator, change 'return' to 'yield' and add 'yield' before calling the function
    and add 'yield' after the function if not returning anything
    """
    stack = []

    def wrappedfunc(*args, **kwargs):
        if stack:
            return f(*args, **kwargs)
        else:
            to = f(*args, **kwargs)
            while True:
                if type(to) is GeneratorType:
                    stack.append(to)
                    to = next(to)
                else:
                    stack.pop()
                    if not stack:
                        break
                    to = stack[-1].send(to)
            return to

    return wrappedfunc


def binary_search(left, right, check, start_from_left):
    if start_from_left:
        ans = left
    else:
        ans = right
    while left <= right:
        mid = (left + right) // 2
        if start_from_left:
            if check(mid):
                ans, left = mid, mid + 1
            else:
                right = mid - 1
        else:
            if check(mid):
                ans, right = mid, mid - 1
            else:
                left = mid + 1
    return ans


execute_once()

if not SKIP_SOLVE:
    for t in range(int(input()) if INPUT_NUMBER_OF_TEST_CASES else 1):
        if BOOLEAN_RETURN:
            print(TRUE_MAPPING if solve(t + 1) else FALSE_MAPPING)
        else:
            solve(t + 1)


Solution 2 (runtime: 2264 ms):
import sys
sys.setrecursionlimit(10**6)
testcases = int(input())
for testcase in range(testcases):
    a = str(input())
    b = str(input())
    c = str(input())
    dp = [[-1 for j in range(len(b) + 1)] for i in range(len(a) + 1)]
    def solve(ptr1, ptr2, a, b, c, dp)-> int:
        if ptr1 == len(a) and ptr2 == len(b):
            return 0
        if dp[ptr1][ptr2] != -1:
            return dp[ptr1][ptr2]
        minChange = 2001
        usingA, usingB = 2001, 2001
        if ptr1 < len(a):
            usingA = solve(ptr1 + 1, ptr2, a, b, c, dp)
            if a[ptr1] != c[ptr1 + ptr2]:
                usingA += 1
        if ptr2 < len(b):
            usingB = solve(ptr1, ptr2 + 1, a, b, c, dp)
            if b[ptr2] != c[ptr1 + ptr2]:
                usingB += 1 
        dp[ptr1][ptr2] = min(usingA, usingB)
        return dp[ptr1][ptr2]
    minChange = solve(0, 0, a, b, c, dp)
    print(minChange)