Problem: 2050E - Three Strings
Language: c++17 

Solution 1 (runtime: 77 ms):
#include <bits/stdc++.h>
using namespace std;

int const MOD = 1e9 + 7;
long long const INF = 1e18; // change accordingly

class sparse_table
{ // range queries for overlap friendly functions in ~O(1); after O(nlogn) build time 
    int n, h; // n = input size (width), h = max power of 2 (height) = log2(n) + 1
    vector<vector<int>> table; // table[x][i] -> ans for next 2^x elements starting at i
    
    public:
    int msb(int i)
    { // get msb => max power of 2 which can fit in x
        return i ? __builtin_clz(1) - __builtin_clz(i) : -1;
    } // replace with _clzll() when using ll, ~ to bit_width - 1 (cpp20)

    sparse_table(vector<int> &nums)
    { // builds by taking entire input array 
        n = nums.size();
        h = msb(n) + 1; // + 1 because 2 ^ h should be last row index

        table = vector<vector<int>>(h, vector<int>(n));
        for (int i = 0; i <= n - 1; i++) table[0][i] = nums[i];

        for (int k = 1; k <= h - 1; k++)
        { // building layers of the table, table[x][i] will contain range answer for [i, i + (1 << x) - 1];  
            for (int i = 0; i <= n - (1 << k); i++) table[k][i] = gcd(table[k - 1][i], table[k - 1][i + (1 << (k - 1))]);
        } // modify the function (here min) with required overlap friendly functionas per problem
    }

    int query(int l, int r)
    { // l, r = 0 based indices for query [l, r];
        int x = msb(r - l + 1);
        return gcd(table[x][l], table[x][r - (1 << x) + 1]);
    } // overlap queries, replace min with required function

}; // overlap friendly functions = min, max, and, or, gcd, lcm. Change query() and constuctor appropriately

void linebreak(int n, int m)
{
    vector<string> s(n);
    for (string &row : s) cin>>row;

    vector<int> sizes;
    for (string &row : s) sizes.push_back(row.size());
    // sort(sizes.begin(), sizes.end());

    int curr = 0, ans = 0;
    for (int i = 0; i <= n - 1; i++)
    {
        curr += sizes[i];
        if (curr <= m) ans = (i + 1);
    }

    cout<<ans<<'\n';
}

// why n >= 3 ??
// pick i = 1 -> n - 2 (0 based)
void transfusion(int n)
{
    vector<int> a(n);
    for (int &ai : a) cin>>ai;

    long long sums[2] = {0}, len[2] = {(n + 1) / 2, n / 2};
    for (int i = 0; i <= n - 1; i++) sums[i & 1] += a[i];
    
    cout<<((sums[0] % len[0]) || (sums[1] % len[1]) || ((sums[0] / len[0]) != (sums[1] / len[1])) ? "NO" : "YES")<<'\n';
}

// dvisible by 9: sum of all digits
// must be divisible by 9
// can only convert 2 and 3, delta = 2, 6
void uninteresting()
{
    string s;
    cin>>s;

    int freq[10] = {0};
    long long sum = 0;

    for (char c : s)
    {
        sum += (c - '0');
        freq[c - '0']++;
    }

    for (int i = 0; i <= freq[3]; i++)
    { // i = freq[3]
        int req = (9 - (sum + 6 * i) % 9) % 9;

        req = (req + ((req & 1) ? 9 : 0)) / 2;
        if (req <= freq[2])
        {
            cout<<"YES"<<'\n';
            return;
        }
    }

    cout<<"NO"<<'\n';
}


// lex max, want to make the first
// char the highest, then second and
// can model a greedy for this
// since decreasing by 1, only need to look
// like 9 steps ahead (with penalty) if bestt is there ?
// then string rotation moment

void shift(vector<int> &a, int const start, int const end)
{
    for (int i = end; i >= start + 1; i--) a[i] = a[i - 1];
}

void digital()
{
    string s;
    cin>>s;

    int const n = s.size();
    vector<int> a(n);
    for (int i = 0; i <= n - 1; i++) a[i] = (s[i] - '0');

    for (int i = 0; i <= n - 1; i++)
    {
        int best = i;
        for (int j = i + 1; j <= n - 1 && j - i <= 9 - a[i]; j++) if (a[best] - (best - i) < a[j] - (j - i)) best = j;

        int val = a[best] - (best - i);
        shift(a, i, best);
        a[i] = val;        
    }

    for (int ai : a) cout<<ai;
    cout<<'\n';
}

// splicing a and b into c
// min: bsoa, dp or greedy
// 1 string is a subsequnce in 
// another pattern: greedy
// but here 2 strings are subsequences

// also constraints can allow n^2
// got some recuccence


void threeStrings()
{ // a + b = c (size)
    string a, b, c;
    cin>>a>>b>>c;

    int const na = a.size(), nb = b.size(), nc = c.size();
    vector<vector<int>> dp(na + 1, vector<int>(nb + 1, MOD));
    dp[na][nb] = 0;

    for (int ia = na; ia >= 0; ia--)
    { // a index
        for (int ib = nb; ib >= 0; ib--)
        { // b index
            if (ia <= na - 1) dp[ia][ib] = min(dp[ia][ib], (a[ia] != c[ia + ib]) + dp[ia + 1][ib]);
            if (ib <= nb - 1) dp[ia][ib] = min(dp[ia][ib], (b[ib] != c[ia + ib]) + dp[ia][ib + 1]);
        }
    }

    cout<<dp[0][0]<<'\n';
}

// queries on segments mmmmm
// also, the infinite case is when
// all elements are equal then modulo infinite
// they will be equal as well

// does not look like BSoA on the query
// some sort of precomp, also, does not need to be
// equal to zero. so no point in finding range gcd
// start assuming numbers

// gcd + phase difference ?
// literally cannot think of BSOA
// assume have to make zero
// then its just range GCD
// after zero, we can increase
// by some values right ?

// some observation: make an array of diff
// and find gcd of those
void modulo(int n, int q)
{
    vector<int> a(n);
    for (int &ai : a) cin>>ai;

    vector<int> diff(n - 1); // (diff[i] = abs(a[i] - a[i + 1]));
    for (int i = 0; i <= n - 2; i++) diff[i] = abs(a[i] - a[i + 1]);
    
    sparse_table diffgcd(diff);

    // cout<<gcd(0, 0)<<'\n';

    while (q--)
    {
        int l, r;
        cin>>l>>r;
        l--, r -= 2;

        if (l > r) cout<<0<<" ";
        else cout<<diffgcd.query(l, r)<<" ";
    }

    cout<<'\n';
}

// assume all paths, destroying 1 with most connected components
// aka the highest degree, is the best choice
// now option is to either continue
// or keep our answer
// looks like tree rerooting ??


int dfs(vector<vector<int>> &graph, vector<int> &degree, int node, int parent)
{
    int ans = degree[node] - (parent >= 0);
    vector<int> vals;
    for (int nei : graph[node])
    {
        if (nei == parent) continue;
        vals.push_back(dfs(graph, degree, nei, node));
    }

    sort(vals.begin(), vals.end(), greater<int>());
    if (parent == -1)
    {
        if (vals.size() >= 1) ans = max(ans, degree[node] - 1 + vals[0]);
        if (vals.size() >= 2) ans = max(ans, degree[node] - 2 + vals[0] + vals[1]);
    }
    else if (vals.size()) ans = max(ans, degree[node] - 2 + vals[0]);

    return ans;
}

void destruction(int n)
{
    vector<vector<int>> edges(n - 1, vector<int>(2)), graph(n);
    for (vector<int> &e : edges) cin>>e[0]>>e[1], e[0]--, e[1]--;

    vector<int> degree(n);
    for (vector<int> &e : edges)
    {
        graph[e[0]].push_back(e[1]), graph[e[1]].push_back(e[0]);
        degree[e[0]]++, degree[e[1]]++;
    }

    int const maxDeg = *max_element(degree.begin(), degree.end());
    int ans = dfs(graph, degree, maxDeg, -1);

    cout<<ans<<'\n';
}

int main()
{
    ios_base::sync_with_stdio(false);
    cin.tie(NULL);

    int t = 1;
    cin>>t;

    while (t--)
    {
        threeStrings();
    }

    return 0;
}

/*
the last dinosaur
i wonder what it saw
when there was nothin anymore

and now you try to soar
upon the wings that youve stolen
from the efforts not of yours
*/

Solution 2 (runtime: 124 ms):
#include <bits/stdc++.h>

#define int long long
using namespace std;
int M = -1e9;
string a,b,c;
int n;
vector<vector<int> >dp;
int rec(int i,int j){
//returns the minimum number of changes in string c when pointers are at i,j,k respectively
    //base case

    if(i+j == n+1){
        return 0;
    }
    
    //cauche check
    if(dp[i][j]!=-1)return dp[i][j];

    //transition
    int ans = 0;
    if(i == a.length()){
        int temp = i+j;
        int k = i+j;
        for(int p=j;p<b.length();++p)
        {
         if(c[k]!=b[p])ans++;
         k++;
        }
        return dp[a.length()][b.length()] = ans;
    }

    else if(j == b.length()){
        int temp = i+j;
        int k = i+j;
        for(int p=i;p<a.length();++p)
        {
         if(c[k]!=a[p])ans++;
         k++;
        }
        return dp[a.length()][b.length()] = ans;
    }
     ans = 1e9+7;
    if(a[i] == c[i+j]){
        ans = min(ans,rec(i+1,j));
    }
    else{
        ans = min(ans,1+rec(i+1,j));
    }
    if(b[j] == c[i+j]){
        ans = min(ans,rec(i,j+1));
    }
    else{
        ans = min(ans,1+rec(i,j+1));
    }
    
    //save and return
    return dp[i][j] =  ans;

}

void solve(){

    cin >> a >> b >> c;
    n = c.length();
    dp.assign(a.length()+1,vector<int>(b.length()+1,-1));
    cout << rec(0,0) << endl;

}

signed main()
{
#ifndef ONLINE_JUDGE
    freopen("input.txt", "r", stdin);
    freopen("output.txt", "w", stdout);
#endif
    int t;
    cin >> t;
   
    while (t--)
    {
       solve();

    }
  
    return 0;
}