using System;
using System.Collections.Generic;
using System.Linq;
class Program
{
static string InputPattern = "InputX";
static List<string> GetInputList()
{
var WillReturn = new List<string>();
if (InputPattern == "Input1") {
WillReturn.Add("abc");
WillReturn.Add("bca");
//10
}
else if (InputPattern == "Input2") {
WillReturn.Add("aa");
WillReturn.Add("aaaaa");
//5
}
else if (InputPattern == "Input3") {
WillReturn.Add("xzyyzxxzyy");
WillReturn.Add("yzxyzyxzyx");
//758
}
else {
string wkStr;
while ((wkStr = Console.ReadLine()) != null) WillReturn.Add(wkStr);
}
return WillReturn;
}
const long Hou = 998244353;
static void Main()
{
List<string> InputList = GetInputList();
string S = InputList[0];
string T = InputList[1];
long Cnt1 = DerivePatternCnt1(S);
long Cnt2 = DerivePatternCnt1(T);
long Cnt3 = DerivePatternCnt2(S, T);
long Answer = Cnt1 + Cnt2 - Cnt3;
Answer %= Hou;
if (Answer < 0) Answer += Hou;
Console.WriteLine(Answer);
}
// 文字列を引数とし、遷移可能ノードのList[現在ノード]を返す
static Dictionary<int, List<int>> DeriveToNodeListDict(string pStr)
{
// 登場ノードのList[文字]
var AppearIndListDict = new Dictionary<char, List<int>>();
// 遷移可能ノードのList[現在ノード]
var ToNodeListDict = new Dictionary<int, List<int>>();
for (int I = pStr.Length - 1; 0 <= I; I--) {
char CurrChar = pStr[I];
if (AppearIndListDict.ContainsKey(CurrChar) == false) {
AppearIndListDict[CurrChar] = new List<int>();
}
AppearIndListDict[CurrChar].Add(I);
ToNodeListDict[I] = new List<int>();
foreach (List<int> EachAppearIndList in AppearIndListDict.Values) {
for (int J = EachAppearIndList.Count - 1; 0 <= J; J--) {
if (EachAppearIndList[J] <= I) {
continue;
}
ToNodeListDict[I].Add(EachAppearIndList[J]);
break;
}
}
}
return ToNodeListDict;
}
// 文字列を引数とし、部分集合の文字列の個数を返す
static long DerivePatternCnt1(string pStr)
{
pStr = 'S' + pStr; // 1文字目は番兵としてSとする
int UB = pStr.Length - 1;
// 遷移可能ノードのList[現在ノード]
var ToNodeListDict = DeriveToNodeListDict(pStr);
// 場合の数[現在ノード]なDP表
long[] DPArr = new long[UB + 1];
DPArr[0] = 1;
// 配るインラインDP
for (int I = 0; I <= UB; I++) {
foreach (int EachToNode in ToNodeListDict[I]) {
DPArr[EachToNode] += DPArr[I];
DPArr[EachToNode] %= Hou;
}
}
long Answer = 0;
for (int I = 1; I <= UB; I++) {
Answer += DPArr[I];
Answer %= Hou;
}
return Answer;
}
// 文字列2つを引数とし、共通の部分集合の文字列の個数を返す
static long DerivePatternCnt2(string pStr1, string pStr2)
{
pStr1 = 'S' + pStr1; // 1文字目は番兵としてSとする
pStr2 = 'S' + pStr2; // 1文字目は番兵としてSとする
int UB1 = pStr1.Length - 1;
int UB2 = pStr2.Length - 1;
// 遷移可能ノードのList[現在ノード]
var ToNodeListDict1 = DeriveToNodeListDict(pStr1);
// 遷移可能ノードのList[現在ノード]
var ToNodeListDict2 = DeriveToNodeListDict(pStr2);
// 場合の数[文字列Sの現在ノード,文字列Tの現在ノード]なDP表
long[,] DPArr = new long[UB1 + 1, UB2 + 1];
DPArr[0, 0] = 1;
// 配るインラインDP
for (int I = 0; I <= UB1; I++) {
for (int J = 0; J <= UB2; J++) {
if (DPArr[I, J] == 0) continue;
foreach (int EachToNode1 in ToNodeListDict1[I]) {
foreach (int EachToNode2 in ToNodeListDict2[J]) {
if (pStr1[EachToNode1] == pStr2[EachToNode2]) {
DPArr[EachToNode1, EachToNode2] += DPArr[I, J];
DPArr[EachToNode1, EachToNode2] %= Hou;
}
}
}
}
}
long Answer = 0;
for (int I = 1; I <= UB1; I++) {
for (int J = 1; J <= UB2; J++) {
Answer += DPArr[I, J];
Answer %= Hou;
}
}
return Answer;
}
}