import java.io.IOException; import java.io.InputStream; import java.io.PrintStream; import java.io.PrintWriter; import java.math.BigInteger; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.NoSuchElementException; import java.util.Random; import java.util.stream.IntStream; import java.util.stream.LongStream; class ModInt { long mod; long[] fac = new long[0]; long[] ifac = new long[0]; long[] inv = new long[0]; long[] fib = new long[0]; public ModInt(long mod) { this.mod = mod; } void expand(int n) { fac = new long[n]; ifac = new long[n]; inv = new long[n]; Arrays.fill(fac, 1); Arrays.fill(ifac, 1); Arrays.fill(inv, 1); for (int i = 2; i < n; ++i) { fac[i] = i * fac[i - 1] % mod; inv[i] = mod - (mod / i) * inv[(int) (mod % i)] % mod; ifac[i] = inv[i] * ifac[i - 1] % mod; } } public long fac(int n) { if (fac.length <= n) { expand(Math.max(2 * fac.length, n + 1)); } return fac[n]; } public long ifac(int n) { if (ifac.length <= n) { expand(Math.max(2 * ifac.length, n + 1)); } return ifac[n]; } public long inv(int n) { if (inv.length <= n) { expand(Math.max(2 * inv.length, n + 1)); } return inv[n]; } public long comb(int n, int k) { if (k < 0 || n - k < 0) return 0; return fac(n) * ifac(k) % mod * ifac(n - k) % mod; } public long fib(int n) { if (fib.length <= n) { fib = new long[2 * Integer.highestOneBit(n)]; fib[0] = 1; fib[1] = 1; for (int i = 2; i < fib.length; ++i) { fib[i] = (fib[i - 1] + fib[i - 2]) % mod; } } return fib[n]; } public long mul(Long...a) { long ret = 1; for (long v : a) ret = ret * v % mod; return ret; } public long pow(long a, long n) { return MathUtils.modPow(a, n, mod); } } class FastScanner { private static FastScanner instance = null; private final InputStream in = System.in; private final byte[] buffer = new byte[1024]; private int ptr = 0; private int buflen = 0; private FastScanner() {} // 外部から new できないようにする public static FastScanner getInstance() { if (instance == null) { instance = new FastScanner(); } return instance; } private boolean hasNextByte() { if (ptr < buflen) return true; ptr = 0; try { buflen = in.read(buffer); } catch (IOException e) { e.printStackTrace(); } return buflen > 0; } private int readByte() { if (hasNextByte()) return buffer[ptr++]; else return -1; } private boolean isPrintableChar(int c) { return 33 <= c && c <= 126; } public boolean hasNext() { while (hasNextByte() && !isPrintableChar(buffer[ptr])) ptr++; return hasNextByte(); } public String next() { if (!hasNext()) throw new NoSuchElementException(); StringBuilder sb = new StringBuilder(); int b = readByte(); while (isPrintableChar(b)) { sb.appendCodePoint(b); b = readByte(); } return sb.toString(); } public long nextLong() { if (!hasNext()) throw new NoSuchElementException(); long n = 0; boolean minus = false; int b = readByte(); if (b == '-') { minus = true; b = readByte(); } while (b >= '0' && b <= '9') { n = n * 10 + (b - '0'); b = readByte(); } return minus ? -n : n; } public int nextInt() { return (int) nextLong(); } public long[] nextLongs(int n) { long[] a = new long[n]; for (int i = 0; i < n; ++i) { a[i] = nextLong(); } return a; } public int[] nextInts(int n) { int[] a = new int[n]; for (int i = 0; i < n; ++i) { a[i] = nextInt(); } return a; } } class PolynomialFp { static long mod = 998244353; public long[] f; static long[][] bitreversedRoots = new long[30][]; static long[][] bitreversedInvRoots = new long[30][]; public PolynomialFp(long[] v) { if (v != null) f = Arrays.copyOf(v, v.length); } public static PolynomialFp of(long[] v) { return new PolynomialFp(v); } static long ADD(long a,long b) { return a+b>=mod?a+b-mod:a+b; } static long SUB(long a,long b) { return ADD(a,mod-b); } static void prepareRoots(int n) { int sz = Integer.numberOfTrailingZeros(n); if (bitreversedRoots[sz] != null) return; long g = 3; long root = MathUtils.modPow(g, (mod - 1) / n, mod); long iroot = MathUtils.modInv(root, mod); bitreversedRoots[sz] = new long[n]; bitreversedInvRoots[sz] = new long[n]; for (int n_ = n / 2; n_ >= 1; n_ /= 2, root = root * root % mod, iroot = iroot * iroot % mod) { long w = 1; long iw = 1; for(int j=0;j(cur^=k);k/=2) ; } } } public static void fft(long[] a, long g) { int n=a.length; { int cur=0; for (int i=0;i(cur^=k);k/=2) ; } } for (int s=1;s<=n/2;s*=2) { long mul=MathUtils.modPow(g,n/(2*s),mod); for (int i=0;i(cur^=k);k/=2) ; } } long invN = MathUtils.modInv(a.length, mod); for (int s=1;s<=n/2;s*=2) { long mul=MathUtils.modPow(g,n/(2*s),mod); for (int i=0;i= 1; m /= 2, t *= 2) { for(int i = 0, k = 0; i rnd.nextInt(start, end)); return ret; } /** * {1,2,..,n} から {start, start+1, .., end - 1} へのランダムな写像 * @param start (inclusive) * @param end (exclusive) * @param length * @return */ public static long[] randomLongArray(long start, long end, int length) { long[] ret = new long[length]; Random rnd=new Random(); Arrays.setAll(ret, i -> rnd.nextLong(start, end)); return ret; } /** * {start, start+1, .., end - 1}^n における辞書順の次の要素にAを変更する。 * @param start (inclusive) * @param end (exclusive) * @param length * @return */ public static boolean nextArray(int[] A, int start, int end) { int t=A.length-1; while(t >= 0 && A[t]==end-1)--t; if(t == -1)return false; A[t]++; for(int i=t+1;i 1) { int m = (ok + ng) / 2; if (a[m] <= key) ok=m; else ng = m; } return ok; } /** * key <= a[i] となる最小の i を返す。aはソートされているとする。 * @param a * @param key * @return */ public static int ceil(int[] a, int key) { int ok = a.length; int ng = -1; while(ok - ng > 1) { int m = (ok + ng) / 2; if (a[m] >= key) ok=m; else ng = m; } return ok; } /** * a[i] <= key となる最大の i を返す。 * @param a * @param key * @return */ public static int floor(long[] a, long key) { int ok = -1; int ng = a.length; while(ng - ok > 1) { int m = (ok + ng) / 2; if (a[m] <= key) ok=m; else ng = m; } return ok; } /** * key <= a[i] となる最小の i を返す。 * @param a * @param key * @return */ public static int ceil(long[] a, long key) { int ok = a.length; int ng = -1; while(ok - ng > 1) { int m = (ok + ng) / 2; if (a[m] >= key) ok=m; else ng = m; } return ok; } /** * 配列を連結する * @param a * @return */ public static long[] concat(long[]... a) { int len = 0; for (int i = 0; i < a.length; ++i) { len += a[i].length; } int src = 0; long[] ret = new long[len]; for (int i = 0; i < a.length; ++i) { for (int j = 0; j < a[i].length; ++j) { ret[src + j] = a[i][j]; } src += a[i].length; } return ret; } public static int[] concat(int[]... a) { int len = 0; for (int i = 0; i < a.length; ++i) { len += a[i].length; } int src = 0; int[] ret = new int[len]; for (int i = 0; i < a.length; ++i) { for (int j = 0; j < a[i].length; ++j) { ret[src + j] = a[i][j]; } src += a[i].length; } return ret; } public static boolean equals(long[] a, long[] b) { if (a.length != b.length) return false; for (int i = 0; i < a.length; ++i) if (a[i] != b[i]) return false; return true; } /** * a.length が2冪を仮定 * @param a */ public static void bitReveseOrder(long[]a) { int n = a.length; int cur=0; for (int i=0;i(cur^=k);k/=2) ; } } /** * a.length が2冪を仮定 * @param a */ public static void bitReveseOrder(int[]a) { int n = a.length; int cur=0; for (int i=0;i(cur^=k);k/=2) ; } } /** * b[i] = a[1] + a[2] + .. + a[i] * @param a * @param mod * @return */ public static long[] modPrefixSum(long[] a, long mod) { long[] b = new long[a.length]; for (int i = 0; i < b.length; ++i) { b[i] = ((i == 0 ? 0 : b[i - 1]) + a[i]) % mod; } return b; } /** * b[i] = a[1] + a[2] + .. + a[i] * @param a * @param mod * @return */ public static long[] prefixSum(long[] a) { long[] b = new long[a.length]; for (int i = 0; i < b.length; ++i) { b[i] = (i == 0 ? 0 : b[i - 1]) + a[i]; } return b; } public static long[][] copy(long[][] a) { long[][] b = new long[a.length][]; Arrays.setAll(b, i -> Arrays.copyOf(a[i], a[i].length)); return b; } public char[][] rightRotateGrid(char[][] a) { char[][] b = new char[a[0].length][a.length]; for (int i = 0; i < a.length; ++i) { for (int j = 0; j < a[i].length; ++j) { b[j][a.length-1-i]=a[i][j]; } } return b; } } class MyPrintWriter extends PrintWriter { public MyPrintWriter(PrintStream out) { super(out); } public void print(long[] a) { print(a, " "); } public void print(int[] a) { print(a, " "); } public void print(int[] a, String separator) { for (int i = 0; i < a.length; ++i) { super.print(a[i]+(i==a.length-1?"\n":separator)); } } public void print(long[] a, String separator) { for (int i = 0; i < a.length; ++i) { super.print(a[i]+(i==a.length-1?"\n":separator)); } } public void printlnYesNo(boolean flag) { println(flag?"Yes":"No"); } } class MathUtils { /** * ニュートン法を用いて、sqrtを計算する。 * x-f(x)/f'(x)=x-(x**2-n)/2x=x-x/2+n/(2x)=(x*x+n)/(2x) */ public static int sqrt(long a) { if(a==0)return 0; long ret=a; while(true) { long nret=(ret+a/ret)/2; if(nret>=ret)break; ret=nret; } return (int)ret; } public static long ceil(long a, long b) { return (a + b - 1) / b; } public static long gcd(long a, long b) { if (a == 0) return b; return gcd(b % a, a); } public static long modPow(long a, long n, long mod) { if (n == 0) return 1; return modPow(a * a % mod, n / 2, mod) * (n % 2 == 1 ? a : 1) % mod; } public static long pow(long a, long n) { if (n == 0) return 1; return pow(a * a, n / 2) * (n % 2 == 1 ? a : 1); } public static long modKthRoot(long a, long k, long mod) { if (k == 0) return a == 1 ? 1 : -1; if (k >0 && a == 0) return 0; long g = gcd(k, mod - 1); if (modPow(a, (mod - 1) / g, mod) != 1) return -1; a = modPow(a, modInv(k / g, (mod - 1) / g), mod); for (long div = 2; div * div <= g; ++div) { int sz = 0; while (g % div == 0) { g /= div; ++sz; } if (sz > 0) { long b = peth_root(a, div, sz, mod); a = b; } } if (g > 1) a = peth_root(a, g, 1, mod); return a; } private static long peth_root(long a, long p, int e, long mod) { long q = mod - 1; int s = 0; while (q % p == 0) { q /= p; ++s; } long pe = modPow(p, e, mod); long ans = modPow(a, ((pe - 1) * modInv(q, pe) % pe * q + 1) / pe, mod); long c = 2; while (modPow(c, (mod - 1) / p, mod) == 1) ++c; c = modPow(c, q, mod); HashMap map = new HashMap<>(); long add = 1; int v = (int) Math.sqrt(p) + 1; long mul = modPow(c, v * modPow(p, s - 1, mod - 1), mod); for (int i = 0; i <= v; ++i) { map.put(add, i); add = add * mul % mod; } mul = modInv(modPow(c, modPow(p, s - 1, mod - 1), mod), mod); out: for (int i = e; i < s; ++i) { long err = modInv(modPow(ans, pe, mod), mod) * a % mod; long target = modPow(err, modPow(p, s - 1 - i, mod - 1), mod); for (int j = 0; j <= v; ++j) { if (map.containsKey(target % mod)) { int x = map.get(target % mod); ans = ans * modPow(c, (j + v * x) * modPow(p, i - e, mod - 1) % (mod - 1), mod) % mod; continue out; } target = target * mul % mod; } throw new AssertionError(); } return ans; } public static long modInv(long a, long mod) { return modPow(a,mod-2,mod); } public static long[] modAdd(long[] a, long[] b, long mod) { if (a.length != b.length) throw new AssertionError(); long[] c = new long[a.length]; for (int i = 0; i < a.length; ++i) { c[i] = a[i] + b[i]; if (c[i] >= mod) c[i] -= mod; } return c; } public static long[] modMul(long[] a, long scalar, long mod) { long[] b = new long[a.length]; for (int i = 0; i < a.length; ++i) { b[i] = a[i] * scalar % mod; } return b; } public static long[] modSub(long[] a, long[] b, long mod) { if (a.length != b.length) throw new AssertionError(); long[] c = new long[a.length]; for (int i = 0; i < a.length; ++i) { c[i] = a[i] - b[i]; if (c[i] < 0) c[i] += mod; } return c; } /** * k = floor(N/i) が等しい区間 1 <= l <= i <= r <= N について組 [l, r, k] を k の昇順(iの降順)に返す。 */ public static ArrayList floorRange(long N) { ArrayList range=new ArrayList<>(); long quotient=1; while(true) { long upper=N/quotient; long lower=N/(quotient+1)+1; range.add(new long[] {lower, upper, quotient}); if(lower==1)break; quotient=N/(lower-1); } return range; } public static String toFibonacciBaseString(long n) { long[] F=new long[92]; F[0]=F[1]=1; for(int i=2;i=0;--i) { if(n>=F[i]) { sb.append("1"); n-=F[i]; }else { sb.append("0"); } } return sb.toString(); } /** * a = sum[i] b[i] 10^i となる b を返す * @param a * @return */ int[] digitsArray(long a) { int[] ret=new int[40]; for(int i=0;i<40;++i) { ret[i]=(int)(a%10); a/=10; if(a==0) return Arrays.copyOf(ret, i + 1); } throw new AssertionError(); } static void tr(Object...objects) { System.out.println(Arrays.deepToString(objects)); } } class Main implements Runnable { // Runnableを実装する public static void main(String[] args) { new Thread(null, new Main(), "", 1024 * 1024 * 1024).start(); // 1024MBスタックを確保して実行 } final long mod=998244353; public void run() { FastScanner sc = FastScanner.getInstance(); MyPrintWriter pw = new MyPrintWriter(System.out); String S=sc.next(); char[]xx=S.toCharArray(); int[]n=new int[xx.length]; Arrays.setAll(n, i->(int)(xx[i]-'0')); long[]poly=new long[10]; long[]mahler=new long[10]; Arrays.fill(poly, 1); Arrays.fill(mahler, 1); mahler[8] = 0; long sub=nthMahler(S, 10, new long[] {1}, PolynomialFp.mul(mahler, poly), mod); sub=(mod-1+sub)%mod; long all=0; for(int i=0;i