B - 1 + 6 = 7
Source: atcoder
Difficulty: 600

Problem Statement
You are given positive integers
A_{1}, A_{2}, A_{3}
. Find the number, modulo
998244353
, of tuples of positive integers
(X_{1}, X_{2}, X_{3})
that satisfy all of the following conditions.
X_{1}
is a positive integer with
A_{1}
digits in decimal notation.
X_{2}
is a positive integer with
A_{2}
digits in decimal notation.
X_{3}
is a positive integer with
A_{3}
digits in decimal notation.
X_{1} + X_{2} = X_{3}
.
You are given
T
test cases per input file; solve each of them.
Constraints
1 \leq T \leq 10^{5}
1 \leq A_{i} \leq 10^{9}
All input values are integers.
Input
The input is given from Standard Input in the following format:
T
\text{case}_{1}
\text{case}_{2}
\vdots
\text{case}_{T}
Each case is given in the following format:
A_{1}
A_{2}
A_{3}
Output
Print
T
lines. The
i
-th line should contain the answer for
\text{case}_{i}
.
Sample Input 1
4
1 1 1
1 6 7
167 167 167
111 666 777
Sample Output 1
36
45
731780675
0
For the first case, tuples such as
(X_{1}, X_{2}, X_{3}) = (1, 6, 7), (2, 1, 3)
satisfy the conditions.
On the other hand, tuples such as
(X_{1}, X_{2}, X_{3}) = (6, 7, 13), (3, 4, 5)
do not.
There are
36
tuples
(X_{1}, X_{2}, X_{3})
that satisfy the conditions, so print
36
.
For the third case, remember to print the result modulo
998244353
.
For the fourth case, there may be no tuples
(X_{1}, X_{2}, X_{3})
that satisfy the conditions.

C++ solution:
#ifndef DEBUG
#pragma GCC optimize("O3,unroll-loops")
// #pragma GCC target("avx2,bmi,bmi2,lzcnt,popcnt")
#endif

#include <bits/stdc++.h>
using namespace std;

#ifdef DEBUG
#include "debug.hpp"
#else
#define debug(...)
#endif

#define rep(i, a, b) for (auto i = a; i < (b); ++i)
#define repr(i, a, b) for (auto i = (a) - 1; i >= (b); --i)
#define pb push_back
#define eb emplace_back
#define all(x) begin(x), end(x)
#define sz(x) int((x).size())
using ll = long long;
using pii = pair<int, int>;
using vi = vector<int>;
using vll = vector<ll>;
using vii = vector<pii>;

template<class T> inline bool cmax(T &a, const T &b)
{ return a < b ? a = b, 1 : 0; }
template<class T> inline bool cmin(T &a, const T &b)
{ return b < a ? a = b, 1 : 0; }

const int inf = 0x3f3f3f3f;
const ll linf = 1e18;
const double dinf = numeric_limits<double>::infinity();


#include <string>
#include <vector>

// Division/inverses only allowed if `md` is prime
template<uint32_t md>
class modint {
    using mint = modint;

    public:
    static constexpr uint32_t mod = md;

    constexpr modint() : x() {}
#define CONSTR(type, utype) \
    constexpr modint(utype x_) : x(x_ < md ? x_ : x_ % md) {} \
    constexpr modint(type  x_) : x(0 <= x_ && (utype) x_ < md ? x_ : ((x_ %= md) < 0 ? x_ + md : x_)) {}
    CONSTR(signed char, unsigned char); CONSTR(signed int, unsigned int);
    CONSTR(signed long, unsigned long); CONSTR(signed long long, unsigned long long);
#ifdef __SIZEOF_INT128__
    CONSTR(__int128_t, __uint128_t);
#endif
#undef CONSTR

    template<typename T>
    static constexpr mint raw(T x) { return {x}; }

    constexpr uint32_t val() const { return x; }
    template<typename T>
    constexpr explicit operator T() const { return T(x); }

    constexpr mint &operator++() { ++x == md ? x = 0 : x; return *this; }
    constexpr mint operator++(int) { uint32_t x_ = x; operator++(); return {x_}; }

    constexpr mint &operator--() { x ? --x : x = md - 1; return *this; }
    constexpr mint operator--(int) { uint32_t x_ = x; operator--(); return {x_};}

    constexpr mint &operator+=(const mint &b) { x < md - b.x ? x += b.x : x += b.x - md; return *this; }
    constexpr mint &operator-=(const mint &b) { x >= b.x ? x -= b.x : x += md - b.x; return *this; }
    constexpr mint &operator*=(const mint &b) { x = uint64_t(x) * b.x % md; return *this; }
    constexpr mint &operator/=(const mint &b) { x = uint64_t(x) * inv_constexpr(b.x) % md; return *this; }

    constexpr friend mint operator+(const mint &a, const mint &b) { return {a.x + b.x - (a.x >= md - b.x) * md}; }
    constexpr friend mint operator-(const mint &a, const mint &b) { return {a.x - b.x + (a.x < b.x) * md}; }
    constexpr friend mint operator*(const mint &a, const mint &b) { return {uint64_t(a.x) * b.x % md}; }
    constexpr friend mint operator/(const mint &a, const mint &b) { return {uint64_t(a.x) * inv_constexpr(b.x) % md}; }

    constexpr mint operator+() const { return {x}; }
    constexpr mint operator-() const { return {x ? md - x : x}; }

#define CMP(c) constexpr friend bool operator c(const mint &a, const mint &b) { return a.x c b.x; }
    CMP(==); CMP(!=); CMP(<); CMP(<=); CMP(>); CMP(>=); 
#undef CMP

    template<typename I>
    friend I &operator>>(I &in, mint &a) { return in >> a.x; }
    template<typename O>
    friend O &operator<<(O &out, const mint &a) { return out << a.x; }

    friend std::string to_string(const mint &a) { return std::to_string(a.x); }

    constexpr mint inv() const { return {inv_constexpr(x)}; }

    static int inv_precomputed_up_to() { return inv_.size() - 1; }
    static int fact_precomputed_up_to() { return fact_.size() - 1; }

    // https://cp-algorithms.com/algebra/module-inverse.html#finding-the-modular-inverse-for-prime-moduli-using-euclidean-division
    static void precompute_inv(uint32_t n) {
        if (n < inv_.size()) return;
        uint32_t a = inv_.size(); inv_.resize(n + 1);
        for (; a <= n; ++a) inv_[a] = md - uint64_t(md / a) * inv_[md % a] % md;
    }

    static void precompute_fact(uint32_t n) {
        if (n < fact_.size()) return;
        precompute_inv(n);
        uint32_t a = fact_.size(); fact_.resize(n + 1); inv_fact_.resize(n + 1);
        for (; a <= n; ++a)
            fact_[a] = uint64_t(fact_[a - 1]) * a % md,
            inv_fact_[a] = uint64_t(inv_fact_[a - 1]) * inv_[a] % md;
    }

    static mint inv(uint32_t n) { return n < inv_.size() ? raw(inv_[n]) : inv_constexpr(n); }
    static mint fact(uint32_t n) { return precompute_fact(n), raw(fact_[n]); }
    static mint inv_fact(uint32_t n) { return precompute_fact(n), raw(inv_fact_[n]); };

    static mint binom(int n, int k) {
        if (n < 0 || k < 0 || k > n) return {0};
        return fact(n) * inv_fact(k) * inv_fact(n - k);
    }
    static mint catalan(int n) { return n < 0 ? raw(0) : binom(2 * n, n) * inv(n + 1); }

    private:
    uint32_t x;

    static inline std::vector<uint32_t> inv_ = {0, 1}, fact_ = {1, 1}, inv_fact_ = {1, 1};

    static constexpr uint32_t inv_constexpr(uint32_t x) {
        uint32_t ans = 1;
        for (uint32_t a = x, b = md - 2; b; b >>= 1, a = uint64_t(a) * a % md) if (b & 1) ans = uint64_t(ans) * a % md;
        return ans;
    }
};

using modint1000000007 = modint<1000000007>;
using modint998244353  = modint<998244353>;

using mint = modint998244353;

mint mpow(mint a, ll e) {
    mint ans = 1;
    for (; e; a *= a, e /= 2) if (e & 1) ans *= a;
    return ans;
}

int main() {
    cin.tie(0)->sync_with_stdio(0);
    cin.exceptions(cin.failbit);

    const int N = 1e6 + 50;
    vector<mint> pw(N);
    pw[0] = 1;
    rep(i, 1, N) pw[i] = pw[i - 1] * 10;

    int t;
    cin >> t;
    while (t--) {
        int a1, a2, a3;
        cin >> a1 >> a2 >> a3;
        if (a2 < a1) {
            swap(a1, a2);
        }
        mint x;
        mint p1 = mpow(10, a1 - 1), p2 = mpow(10, a2 - 1);
        if (a1 == a2) {
            x = 8*p1 * (8*p1 + 1) / 2;
        } else {
            x = 9*p1 * (9*p2 - (p1 + 10*p1 - 1) / 2);
        }
        if (a3 == a2) {
            cout << x << '\n';
        } else if (a3 == a2 + 1) {
            cout << (9*p1)*(9*p2) - x << '\n';
        } else {
            cout << 0 << '\n';
        }
    }

    return 0;
}

Go solution:
package main

import (
	"bufio"
	"fmt"
	"os"
	"strconv"
)

var (
	sc = bufio.NewScanner(os.Stdin)
	wt = bufio.NewWriter(os.Stdout)
)

const (
	inf = 1 << 60
	MOD = 998244353
)

func main() {
	/*** INIT ***/
	defer wt.Flush()
	sc.Buffer([]byte{}, inf)
	sc.Split(bufio.ScanWords)

	t := InputInt()
	// seen := make(map[int]int)

	for 0 < t {
		t--
		a, b, c := InputInt(), InputInt(), InputInt()
		if b < a {
			a, b = b, a
		}
		div2 := MOD - (MOD/2)%MOD
		OutInt(solve(a, b, c, div2))
	}
}

func solve(a, b, c, div2 int) int {
	if b != c && b+1 != c {
		return 0
	}
	if b != c {
		ret := 81*ModPow(10, a+b-2, MOD) - solve(a, b, b, div2) + MOD
		return (ret % MOD)
	}
	if a == b {
		ans1 := 8 * ModPow(10, a-1, MOD) % MOD
		ans1 = (ans1 * (ans1 + 1) % MOD) % MOD
		ans1 = (ans1 * div2) % MOD
		return ans1
	} else {
		ans2 := (ModPow(10, a-1, MOD) + ModPow(10, a, MOD) - 1 + MOD) % MOD
		ans2 = (ans2 * div2) % MOD
		ans2 = (9*ModPow(10, b-1, MOD) - ans2 + MOD) % MOD
		ans2 = ((9 * ModPow(10, a-1, MOD)) % MOD * ans2) % MOD
		return ans2
	}
}

// compute (x^k)%m with O(log k)
// (x^{-1})%m = ModPow(x, m-2, m) (for prime m)
func ModPow(x, k, m int) int {
	if k == 0 {
		return 1
	}
	if k%2 == 0 {
		return ModPow(x*x%m, k/2, m)
	} else {
		return x * ModPow(x, k-1, m) % m
	}
}

/*** I/O ***/
func InputInt() int {
	sc.Scan()
	val, _ := strconv.Atoi(sc.Text())
	return val
}

func InputString() string {
	sc.Scan()
	return sc.Text()
}

func OutInt(val int) {
	fmt.Fprintln(wt, val)
}

func OutString(s string) {
	fmt.Fprintln(wt, s)
}

Java solution:
import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.StringJoiner;
import java.util.function.IntUnaryOperator;
import java.util.function.LongUnaryOperator;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

import static java.lang.Math.max;

public class Main {
    static In in = new In();
    static Out out = new Out(false, false);
    static final long inf = 0x1fffffffffffffffL;
    static final int iinf = 0x3fffffff;
    static final double eps = 1e-9;
    static long mod = 998244353;

    void solve() {
//        long acc = 0;
//        for (int i = 10000; i < 100000; i++) {
//            for (int j = 10000; j < 100000; j++) {
//                if (10000 <= i + j && i + j < 100000) {
//                    acc++;
//                }
//            }
//        }
//        out.debug(acc % mod);
        int t = in.nextInt();
        while (t --> 0) {
            long a1 = in.nextLong();
            long a2 = in.nextLong();
            long a3 = in.nextLong();
            if (max(a1, a2) + 1 < a3 || max(a1, a2) > a3) {
                out.println(0);
                continue;
            }
            if (a1 > a2) {
                long temp = a1;
                a1 = a2;
                a2 = temp;
            }
            if (a1 < a2) {
                long over = sum(a1);
                if (a2 == a3) {
                    out.println((cnt(a2) * cnt(a1) % mod + mod - over) % mod);
                } else {
                    out.println(over);
                }
            } else {
                long p10 = pow(10, a1 - 1);
                long over = (p10 * p10 % mod * 49 - p10 * 4 % mod + mod) % mod;
                if (a2 == a3) {
                    out.println((cnt(a2) * cnt(a1) % mod + mod - over) % mod);
                } else {
                    out.println(over);
                }
            }
        }
    }

    long cnt(long a) {
        return pow(10, a - 1) * 9 % mod;
    }

    long sum(long a) {
        long p10a = pow(10, a - 1);
        long p10b = p10a * 10 % mod;
        long s1 = (p10a + mod - 1) * p10a % mod * inv2 % mod;
        long s2 = (p10b + mod - 1) * p10b % mod * inv2 % mod;
        return (s2 - s1 + mod) % mod;
    }

    final long inv2 = (mod + 1) / 2;

    public long pow(long a, long b) {
        long x = 1;
        while (b > 0) {
            if ((b & 1) == 1) {
                x = x * a % mod;
            }
            a = a * a % mod;
            b >>= 1;
        }
        return x;
    }

    public static void main(String... args) {
        new Main().solve();
        out.flush();
    }
}

class In {
    private final BufferedInputStream reader = new BufferedInputStream(System.in);
    private final byte[] buffer = new byte[0x10000];
    private int i = 0;
    private int length = 0;

    public int read() {
        if (i == length) {
            i = 0;
            try {
                length = reader.read(buffer);
            } catch (IOException ignored) {
            }
            if (length == -1) {
                return 0;
            }
        }
        if (length <= i) {
            throw new RuntimeException();
        }
        return buffer[i++];
    }

    public String next() {
        StringBuilder builder = new StringBuilder();
        int b = read();
        while (b < '!' || '~' < b) {
            b = read();
        }
        while ('!' <= b && b <= '~') {
            builder.appendCodePoint(b);
            b = read();
        }
        return builder.toString();
    }

    public String nextLine() {
        StringBuilder builder = new StringBuilder();
        int b = read();
        while (b != 0 && b != '\r' && b != '\n') {
            builder.appendCodePoint(b);
            b = read();
        }
        if (b == '\r') {
            read();
        }
        return builder.toString();
    }

    public int nextInt() {
        long val = nextLong();
        if (val < Integer.MIN_VALUE || Integer.MAX_VALUE < val) {
            throw new NumberFormatException();
        }
        return (int)val;
    }

    public long nextLong() {
        int b = read();
        while (b < '!' || '~' < b) {
            b = read();
        }
        boolean neg = false;
        if (b == '-') {
            neg = true;
            b = read();
        }
        long n = 0;
        int c = 0;
        while ('0' <= b && b <= '9') {
            n = n * 10 + b - '0';
            b = read();
            c++;
        }
        if (c == 0 || c >= 2 && n == 0) {
            throw new NumberFormatException();
        }
        return neg ? -n : n;
    }

    public double nextDouble() {
        return Double.parseDouble(next());
    }

    public char[] nextCharArray() {
        return next().toCharArray();
    }

    public String[] nextStringArray(int n) {
        String[] s = new String[n];
        for (int i = 0; i < n; i++) {
            s[i] = next();
        }
        return s;
    }

    public char[][] nextCharMatrix(int n, int m) {
        char[][] a = new char[n][m];
        for (int i = 0; i < n; i++) {
            a[i] = next().toCharArray();
        }
        return a;
    }

    public int[] nextIntArray(int n) {
        int[] a = new int[n];
        for (int i = 0; i < n; i++) {
            a[i] = nextInt();
        }
        return a;
    }

    public int[] nextIntArray(int n, IntUnaryOperator op) {
        int[] a = new int[n];
        for (int i = 0; i < n; i++) {
            a[i] = op.applyAsInt(nextInt());
        }
        return a;
    }

    public int[][] nextIntMatrix(int h, int w) {
        int[][] a = new int[h][w];
        for (int i = 0; i < h; i++) {
            a[i] = nextIntArray(w);
        }
        return a;
    }

    public long[] nextLongArray(int n) {
        long[] a = new long[n];
        for (int i = 0; i < n; i++) {
            a[i] = nextLong();
        }
        return a;
    }

    public long[] nextLongArray(int n, LongUnaryOperator op) {
        long[] a = new long[n];
        for (int i = 0; i < n; i++) {
            a[i] = op.applyAsLong(nextLong());
        }
        return a;
    }

    public long[][] nextLongMatrix(int h, int w) {
        long[][] a = new long[h][w];
        for (int i = 0; i < h; i++) {
            a[i] = nextLongArray(w);
        }
        return a;
    }

    public List<List<Integer>> nextGraph(int n, int m, boolean directed) {
        List<List<Integer>> res = new ArrayList<>();
        for (int i = 0; i < n; i++) {
            res.add(new ArrayList<>());
        }
        for (int i = 0; i < m; i++) {
            int u = nextInt() - 1;
            int v = nextInt() - 1;
            res.get(u).add(v);
            if (!directed) {
                res.get(v).add(u);
            }
        }
        return res;
    }
}

class Out {
    private final PrintWriter out = new PrintWriter(System.out);
    private final PrintWriter err = new PrintWriter(System.err);
    public boolean autoFlush;
    public boolean enableDebug;

    public Out(boolean autoFlush, boolean enableDebug) {
        this.autoFlush = autoFlush;
        this.enableDebug = enableDebug;
    }

    public void debug(Object... args) {
        if (!enableDebug) {
            return;
        }
        if (args == null || args.getClass() != Object[].class) {
            args = new Object[] {args};
        }
        err.println(Arrays.stream(args).map(obj -> format(obj, true)).collect(Collectors.joining(" ")));
        err.flush();
    }

    private String format(Object obj, boolean canMultiline) {
        if (obj == null) return "null";
        Class<?> clazz = obj.getClass();
        if (clazz == Double.class) return String.format("%.10f", obj);
        if (clazz == int[].class) return Arrays.toString((int[])obj);
        if (clazz == long[].class) return Arrays.toString((long[])obj);
        if (clazz == char[].class) return String.valueOf((char[])obj);
        if (clazz == boolean[].class) return IntStream.range(0, ((boolean[])obj).length).mapToObj(i -> ((boolean[])obj)[i] ? "1" : "0").collect(Collectors.joining());
        if (clazz == double[].class) return Arrays.toString(Arrays.stream((double[])obj).mapToObj(a -> format(a, false)).toArray());
        if (canMultiline && clazz.isArray() && clazz.componentType().isArray()) return Arrays.stream((Object[])obj).map(a -> format(a, false)).collect(Collectors.joining("\n"));
        if (clazz == Object[].class) return Arrays.toString(Arrays.stream((Object[])obj).map(a -> format(a, false)).toArray());
        if (clazz.isArray()) return Arrays.toString((Object[])obj);
        return String.valueOf(obj);
    }

    public void println(Object... args) {
        if (args == null || args.getClass() != Object[].class) {
            args = new Object[] {args};
        }
        out.println(Arrays.stream(args)
                .map(obj -> obj instanceof Double ? String.format("%.10f", obj) : String.valueOf(obj))
                .collect(Collectors.joining(" ")));
        if (autoFlush) {
            out.flush();
        }
    }

    public void println(char a) {
        out.println(a);
        if (autoFlush) {
            out.flush();
        }
    }

    public void println(int a) {
        out.println(a);
        if (autoFlush) {
            out.flush();
        }
    }

    public void println(long a) {
        out.println(a);
        if (autoFlush) {
            out.flush();
        }
    }

    public void println(double a) {
        out.println(String.format("%.10f", a));
        if (autoFlush) {
            out.flush();
        }
    }

    public void println(String s) {
        out.println(s);
        if (autoFlush) {
            out.flush();
        }
    }

    public void println(char[] s) {
        out.println(String.valueOf(s));
        if (autoFlush) {
            out.flush();
        }
    }

    public void println(int[] a) {
        StringJoiner joiner = new StringJoiner(" ");
        for (int i : a) {
            joiner.add(Integer.toString(i));
        }
        out.println(joiner);
        if (autoFlush) {
            out.flush();
        }
    }

    public void println(long[] a) {
        StringJoiner joiner = new StringJoiner(" ");
        for (long i : a) {
            joiner.add(Long.toString(i));
        }
        out.println(joiner);
        if (autoFlush) {
            out.flush();
        }
    }

    public void flush() {
        err.flush();
        out.flush();
    }
}

JavaScript solution:
"use strict";
var input=require("fs").readFileSync("/dev/stdin","utf8");
var cin=input.split(/ |\n/),cid=0;
function next(){return +cin[cid++];}
function nextstr(){return cin[cid++];}
function nextbig(){return BigInt(cin[cid++]);}
function nexts(n,a){return a?cin.slice(cid,cid+=n):cin.slice(cid,cid+=n).map(a=>+a);}
function nextssort(n,a){return a?cin.slice(cid,cid+=n).map(a=>+a).sort((a,b)=>b-a):cin.slice(cid,cid+=n).map(a=>+a).sort((a,b)=>a-b);}
function nextm(h,w,a){var r=[],i=0;if(a)for(;i<h;i++)r.push(cin.slice(cid,cid+=w));else for(;i<h;i++)r.push(cin.slice(cid,cid+=w).map(a=>+a));return r;}
function xArray(v){var a=arguments,l=a.length,r="Array(a["+--l+"]).fill().map(x=>{return "+v+";})";while(--l)r="Array(a["+l+"]).fill().map(x=>"+r+")";return eval(r);}
var streams=[];function print(s){streams.push(s);}

const mod = 998244353;
const modx=0x10000000000%mod;
function mul(){for(var a=arguments,r=a[0],i=a.length;--i;)r=((r>>20)*(a[i]>>20)*modx+(r&0xfff00000)*(a[i]&0xfffff)+(r&0xfffff)*a[i])%mod;return r;}
var fac=[],finv=[],invs=[],pow2=[];
function fset(n){
  fac.length=n+1,fac[0]=fac[1]=1;
  for(var i=2;i<=n;)fac[i]=mul(fac[i-1],i++);
  finv.length=n+1,finv[0]=finv[1]=1,finv[n]=inv(fac[n]);
  for(i=n;2<i;)finv[i-1]=mul(finv[i],i--);
  //invs.length=n+1,invs[0]=invs[1]=1;
  //for(i=2;i<=n;)invs[i]=mul(fac[i-1],finv[i++]);
  //pow2.length=n+1,pow2[0]=1;
  //for(i=1;i<=n;i++)pow2[i]=pow2[i-1]*2%mod;
}
function inv(x){for(var a=1,b=0,y=mod,q;y;[b,a]=[a,b-q*a])q=y/x|0,[y,x]=[x,y-q*x];return a<0?a+mod:a;}
function pow(a,n){for(var r=1;n;n>>=1,a=mul(a,a)){while(!(n&1))n>>=1,a=mul(a,a);r=mul(a,r);}return r;}
function ncr(n,r){return mul(fac[n],finv[r],finv[n-r]);}
function npr(n,r){return mul(fac[n],finv[n-r]);}
function mput(n){return (n%mod+mod)%mod;}
var i2 = inv(2);
var myOut = main();
if(myOut !== undefined)console.log(String(myOut));
if(streams.length)console.log(streams.join("\n"));

function main(){
  var q = next();
  while(q--)print(solve());
}

function solve(){
  var a = nexts(3);
  if(a[0] > a[1])[a[0], a[1]] = [a[1], a[0]];
  if(a[2] < a[1] || a[2] > a[1]+1)return 0;
  if(a[2] === a[1]+1){
    if(a[0] === a[1]){
      var t = f(pow(10,a[0]-1), mput(pow(10,a[0])-pow(10,a[0]-1)));
      var u = mul(pow(10,a[0]-1)-1, mput(pow(10,a[0])-pow(10,a[0]-1)));
      return mput(t+u);
    }
    return f(pow(10,a[0]-1), pow(10,a[0])-1);
  }else{
    if(a[0] === a[1])
      return f(1 , mput(pow(10,a[1]) - pow(10,a[1]-1) - pow(10,a[0]-1)));
    return f(mput(pow(10,a[1]) - pow(10,a[1]-1) - pow(10,a[0]) + 1) , mput(pow(10,a[1]) - pow(10,a[1]-1) - pow(10,a[0]-1)));
  }
}
function f(a,b){
  return mul(mput(a+b), mput(b-a+1), i2);
}

Python solution:
mod = 998244353
T = int(input())
inv2 = pow(2, -1, mod)
def solve(a1, a2, a3):
    if a1 > a2:
        a1, a2 = a2, a1
    if a3 < a2 or a3 > a2 + 1:
        return 0
    if a2 == a3:
        temp1 = pow(10, a1-1, mod)
        if a1 == a2:
            return 4 * temp1 * (8 * temp1 + 1) % mod
        # a1 < a2
        return 9 * temp1 * (9 * pow(10, a2-1, mod) - (temp1 + pow(10, a1, mod) - 1) * inv2) % mod
    if a2 < a3:
        return (81 * pow(10, a1 + a2 - 2, mod) - solve(a1, a2, a2)) % mod
        
ans = []
for _ in range(T):
    a1, a2, a3 = map(int, input().split())
    ans.append(solve(a1, a2, a3))
for x in ans:
    print(x)

Ruby solution:
END { load __FILE__ unless $stdin.eof? }
@m = 998_244_353

gets.to_i.times do

a1, a2, a3 = gets.split.map!(&:to_i)

a1, a2 = a2, a1 if a1 > a2

if a2 + 1 == a3
  if a1 == a2
    m = 10.pow(a1.pred, @m)
    puts (m * 8 * (m * 10 - 1) / 2 + m * 9 * m) % @m
  else
    m = 10.pow(a1.pred, @m)
    puts (m * 11 - 1) * (m * 9) / 2 % @m
  end
elsif a2 == a3
  if a1 == a2
    m = 8 * 10.pow(a1.pred, @m)
    puts m * m.succ / 2 % @m
  else
    m = 9 * 10.pow(a1.pred, @m)
    m2 = 9 * 10.pow(a2.pred, @m)
    puts (m * m.succ / 2 + m * (m2 - m / 9 * 10)) % @m
  end
else
  puts 0
end

end

__END__