#include <bits/stdc++.h>
using namespace std;
static const int MAXLEN = 15;
static const int MAXSUM = 9 * MAXLEN; // 135
static bool isPrimeSum[MAXSUM + 1];
static unsigned long long ways[MAXLEN + 1][MAXSUM + 1];
static unsigned long long cntGoodSuffix[MAXLEN + 1][MAXSUM + 1];
static unsigned long long totalGoodLen[MAXLEN + 1];
static void precompute_global() {
// Sieve primes up to 135
vector<bool> isPrime(MAXSUM + 1, true);
isPrime[0] = isPrime[1] = false;
for (int p = 2; p * p <= MAXSUM; ++p) {
if (isPrime[p]) {
for (int q = p * p; q <= MAXSUM; q += p) isPrime[q] = false;
}
}
for (int i = 0; i <= MAXSUM; ++i) isPrimeSum[i] = isPrime[i];
// ways[len][sum]
memset(ways, 0, sizeof(ways));
ways[0][0] = 1;
for (int len = 1; len <= MAXLEN; ++len) {
for (int s = 0; s <= 9 * len; ++s) {
unsigned long long v = 0;
for (int d = 0; d <= 9; ++d) {
if (s - d >= 0) v += ways[len - 1][s - d];
}
ways[len][s] = v;
}
}
// cntGoodSuffix[rem][sumPrefix]
for (int rem = 0; rem <= MAXLEN; ++rem) {
for (int sumPrefix = 0; sumPrefix <= MAXSUM; ++sumPrefix) {
unsigned long long total = 0;
for (int t = 0; t <= 9 * rem; ++t) {
int totSum = sumPrefix + t;
if (totSum <= MAXSUM && isPrimeSum[totSum]) {
total += ways[rem][t];
}
}
cntGoodSuffix[rem][sumPrefix] = total;
}
}
// totalGoodLen[L]: count of good L-digit numbers (leading digit != 0)
for (int L = 1; L <= MAXLEN; ++L) {
if (L == 1) {
unsigned long long c = 0;
for (int d = 1; d <= 9; ++d) if (isPrimeSum[d]) ++c;
totalGoodLen[L] = c;
} else {
unsigned long long c = 0;
for (int first = 1; first <= 9; ++first) {
c += cntGoodSuffix[L - 1][first];
}
totalGoodLen[L] = c;
}
}
}
struct Solver {
string pat;
int m;
// KMP transitions: for state 0..m-1 and digit 0..9 -> next state (0..m)
vector<array<uint8_t, 10>> kmpTrans;
// monoid states for prefixes (merged):
// For each monoidId and each startState (0..m-1):
// - monMatch: 1 if the pattern appears while reading this prefix
// - monEnd : resulting KMP state after reading the prefix, assuming no match inside
vector<vector<uint8_t>> monEnd;
vector<vector<uint8_t>> monMatch;
vector<array<int, 10>> monNext;
// DP memo: key -> encoded result
// result encoding: high bit (0x8000) = match, else value = endState
unordered_map<uint64_t, uint16_t> dp;
static constexpr uint16_t MATCH_CODE = 0x8000;
explicit Solver(string p) : pat(std::move(p)), m((int)pat.size()) {}
void buildKMP() {
vector<int> pi(m, 0);
for (int i = 1, j = 0; i < m; ++i) {
while (j > 0 && pat[i] != pat[j]) j = pi[j - 1];
if (pat[i] == pat[j]) ++j;
pi[i] = j;
}
kmpTrans.assign(m, array<uint8_t, 10>{});
for (int st = 0; st < m; ++st) {
for (int d = 0; d <= 9; ++d) {
char c = char('0' + d);
int j = st;
while (j > 0 && pat[j] != c) j = pi[j - 1];
if (pat[j] == c) ++j;
kmpTrans[st][d] = (uint8_t)j; // can be m
}
}
}
void buildMonoidStates() {
monEnd.clear();
monMatch.clear();
monNext.clear();
vector<uint8_t> end0(m), match0(m, 0);
for (int s = 0; s < m; ++s) end0[s] = (uint8_t)s;
auto makeKey = [&](const vector<uint8_t>& en, const vector<uint8_t>& ma) -> string {
string key;
key.resize((size_t)2 * m);
for (int i = 0; i < m; ++i) key[i] = (char)en[i];
for (int i = 0; i < m; ++i) key[m + i] = (char)ma[i];
return key;
};
unordered_map<string, int> idMap;
idMap.reserve(4096);
idMap.max_load_factor(0.7f);
string key0 = makeKey(end0, match0);
idMap.emplace(key0, 0);
monEnd.push_back(end0);
monMatch.push_back(match0);
monNext.push_back(array<int, 10>{});
for (int d = 0; d < 10; ++d) monNext[0][d] = -1;
queue<pair<int, int>> q; // (id, length)
q.push({0, 0});
while (!q.empty()) {
auto [sid, len] = q.front();
q.pop();
if (len == MAXLEN) continue;
for (int d = 0; d <= 9; ++d) {
vector<uint8_t> enNew(m, 0), maNew(m, 0);
const auto& enOld = monEnd[sid];
const auto& maOld = monMatch[sid];
for (int s = 0; s < m; ++s) {
if (maOld[s]) {
maNew[s] = 1;
enNew[s] = 0;
} else {
int cur = enOld[s]; // < m
int ns = kmpTrans[cur][d];
if (ns == m) {
maNew[s] = 1;
enNew[s] = 0;
} else {
maNew[s] = 0;
enNew[s] = (uint8_t)ns;
}
}
}
string key = makeKey(enNew, maNew);
auto it = idMap.find(key);
int nid;
if (it == idMap.end()) {
nid = (int)monEnd.size();
idMap.emplace(std::move(key), nid);
monEnd.push_back(std::move(enNew));
monMatch.push_back(std::move(maNew));
monNext.push_back(array<int, 10>{});
for (int dd = 0; dd < 10; ++dd) monNext[nid][dd] = -1;
q.push({nid, len + 1});
} else {
nid = it->second;
}
monNext[sid][d] = nid;
}
}
}
static inline uint64_t packKey(int rem, int sum, int monoidId, int startState, bool firstFlag) {
// bits: rem(4) sum(8) monoid(13) start(7) first(1)
return (uint64_t)rem
| ((uint64_t)sum << 4)
| ((uint64_t)monoidId << 12)
| ((uint64_t)startState << 25)
| ((uint64_t)(firstFlag ? 1 : 0) << 32);
}
inline uint16_t solve(int rem, int sum, int monoidId, int startState, bool firstFlag) {
if (startState == m) return MATCH_CODE;
uint64_t key = packKey(rem, sum, monoidId, startState, firstFlag);
auto it = dp.find(key);
if (it != dp.end()) return it->second;
uint16_t ans = 0;
if (rem == 0) {
if (!isPrimeSum[sum]) {
ans = (uint16_t)startState;
} else if (monMatch[monoidId][startState]) {
ans = MATCH_CODE;
} else {
ans = (uint16_t)monEnd[monoidId][startState];
}
} else {
if (cntGoodSuffix[rem][sum] == 0ULL) {
// no good numbers at all in this subtree => empty output
ans = (uint16_t)startState;
} else {
int cur = startState;
int d0 = firstFlag ? 1 : 0;
bool found = false;
for (int d = d0; d <= 9; ++d) {
int newSum = sum + d;
if (newSum > MAXSUM) continue;
if (cntGoodSuffix[rem - 1][newSum] == 0ULL) continue;
int childId = monNext[monoidId][d];
uint16_t childRes = solve(rem - 1, newSum, childId, cur, false);
if (childRes & MATCH_CODE) {
ans = MATCH_CODE;
found = true;
break;
}
cur = (int)childRes; // endState
}
if (!found) ans = (uint16_t)cur;
}
}
dp.emplace(key, ans);
return ans;
}
unsigned long long findEndPosInLengthGroup(
int L, int rem, int sum, int monoidId, int startState, bool firstFlag,
unsigned long long offset, char digits[], int depth
) {
if (rem == 0) {
int cur = startState;
for (int i = 0; i < L; ++i) {
int d = digits[i] - '0';
cur = kmpTrans[cur][d];
if (cur == m) {
return offset + (unsigned long long)(i + 1); // 1-indexed within the number
}
}
// should not happen
return offset + (unsigned long long)L;
}
int cur = startState;
int d0 = firstFlag ? 1 : 0;
for (int d = d0; d <= 9; ++d) {
int newSum = sum + d;
if (newSum > MAXSUM) continue;
unsigned long long countChild = cntGoodSuffix[rem - 1][newSum];
if (countChild == 0ULL) continue;
int childId = monNext[monoidId][d];
uint16_t childRes = solve(rem - 1, newSum, childId, cur, false);
if (childRes & MATCH_CODE) {
digits[depth] = char('0' + d);
return findEndPosInLengthGroup(L, rem - 1, newSum, childId, cur, false, offset, digits, depth + 1);
} else {
offset += countChild * (unsigned long long)L;
cur = (int)childRes;
}
}
// should not happen
return offset;
}
unsigned long long solveOne() {
buildKMP();
buildMonoidStates();
dp.clear();
dp.reserve(200000);
dp.max_load_factor(0.7f);
unsigned long long posBefore = 0; // digits before current length group
int curState = 0;
for (int L = 1; L <= MAXLEN; ++L) {
uint16_t res = solve(L, 0, 0, curState, true);
if (!(res & MATCH_CODE)) {
posBefore += totalGoodLen[L] * (unsigned long long)L;
curState = (int)res;
} else {
char digits[MAXLEN];
unsigned long long endPosInGroup =
findEndPosInLengthGroup(L, L, 0, 0, curState, true, 0ULL, digits, 0);
unsigned long long globalEnd = posBefore + endPosInGroup;
unsigned long long startPos = globalEnd - (unsigned long long)m + 1ULL;
return startPos;
}
}
// Input guarantees pattern exists
return 0;
}
};
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
precompute_global();
int T;
cin >> T;
while (T--) {
string x;
cin >> x;
Solver solver(x);
cout << solver.solveOne() << "\n";
}
return 0;
}