#yukicoder 2810 Have Another Go(Hard) ''' 1. ライブラリの登録 ''' #kitamasa法 隣接k項間漸化式の特定項を算出する #F(x): [P0,P1, ... , Pk-1] Px: Ax=sum(Pi*Ai) [0<=i (1 + M) * N: continue dp[k + L] += dp[k] dp[k + L] %= MOD A[i][j] = dp[(1 + M) * N - j] return A ''' 3. 入力受取と各種初期設定 kitamasa法まわりを設定 ''' N, M, K = map(int, input().split()) C = list(map(int, input().split())) MOD = 998244353 kit = kitamasa(6, [1] * 6, 1, MOD) MP = matrix_pow(MOD) def calc_move(x): #マス0から開始して、ちょうどマスxに到達するときの寄与 F = [1, 0, 0, 0, 0, 0] for i in bin(x)[2:]: F = kit.mul(F) if i == '1': F = kit.add(F) return F def calc_dict(x_list): #計算したい「ちょうどxマス」の一覧を渡す。全部計算する #1. ソートしてから重複を削除 x_list = sorted(x_list) x2 = [] while x_list: x = x_list.pop() if len(x2) == 0 or x2[-1] != x: x2.append(x) #2. 計算 sub = dict() back = 0 F = [1, 0, 0, 0, 0, 0] while x2: now = x2.pop() assert back <= now diff = now - back if diff < 40: #毎回再生成はコストが重いので、addで歩ける範囲は歩く for _ in range(diff): F = kit.add(F) else: F = calc_move(now) sub[now] = kit.get(F) back = now return sub #sub[i]: ちょうどiマス目に止まる場合の数 を前計算しておく。行列Aを返す。 #A[i][j]: (1 + 0)N - 5 ~ (1 + 0)N - 0のうちはじめて踏んだマスである(1 + 0)N - iから始め、 # (1 + M)N - 5 ~ (1 + M)N - 0のうちはじめて踏んだマスである(1 + M)N - jで終わる # 移動経路のうち、Ci mod Nを踏まない場合の数 def calc_matrix(Ci, sub): #Nが小さいときは愚直な計算でよい  O(N * 6^3) if N < 12: return brute_matrix(N, 1, Ci) #Nが大きい場合のみを考える assert N >= 12 A = [[0] * 6 for _ in range(6)] for i in range(6): #dp[x]: N - iマス目から始めて、ちょうど2 * N - xマス目に止まる場合の数。 # ただし Ci mod Nマス目には止まらない # 特に x <= 5: 2 * N - (0 ~ 5)ではじめて止まったマスが2 * N - x dp = [0] * 11 #i == 5, Ci == N - 5の場合は例外処理(常に0になる) if i == 5 and Ci == N - 5: continue #(N - 5 <=) N - i <= t <= 2 * N - (10 ~ 5) (<= 2 * N - 5), #t % N == Ci となるtは高々1個である。この性質を活かしてdp[5 ~ 10]を埋める t = Ci if N - 5 < Ci else N + Ci for x in range(5, 11): if N - i <= t <= 2 * N - x: d1 = t - (N - i) d2 = (2 * N - x) - t dp[x] = sub[d1 + d2] - sub[d1] * sub[d2] dp[x] %= MOD else: dp[x] = sub[(2 * N - x) - (N - i)] #もらうdpでdp[0:5]を埋める for x in range(5): if (-x) % N == Ci: continue for k in range(1, 7): y = x + k #元々のマス if y <= 5: continue dp[x] += dp[y] dp[x] %= MOD #A[i][j]に反映 for j in range(6): A[i][j] = dp[j] % MOD return A #calc_matrixで必要な値を列挙する def listup(C): x_list = [] for Ci in C: for i in range(6): t = Ci if N - 5 < Ci else N + Ci for x in range(5, 11): if N - i <= t <= 2 * N - x: d1 = t - (N - i) d2 = (2 * N - x) - t x_list.append(d1) x_list.append(d2) x_list.append(d1 + d2) else: x_list.append((2 * N - x) - (N - i)) return x_list #計算を実行 def solve(N, M, C): #1. subを前計算 包除で使いたいのでN * M - (0 ~ 5)も計算する sub = calc_dict([N * M - i for i in range(6)] + listup(C)) #2. 包除元を計算: N * Mマス以降に到達する場合の数 dp = [sub[N * M - i] for i in range(6)] base = dp[0] for i in range(1, 6): base += dp[i] * (6 - i) #N * Mマス目以降に到達する場合の数 base %= MOD #3. 行列累乗を実行 Ciを踏まずにN * Mマス以降に到達する場合の数を計算 for Ci in C: A = calc_matrix(Ci, sub) E = MP.eye(6) for i in bin(M)[2:]: E = MP.mul(E, E) if i == '1': E = MP.mul(E, A) dp = MP.mul([[1, 0, 0, 0, 0, 0]], E)[0] for i in range(5, 0, -1): if (-i) % N == Ci: dp[i] = 0 for k in range(1, 7): dp[max(0, i - k)] += dp[i] dp[max(0, i - k)] %= MOD print((base - dp[0]) % MOD) solve(N, M, C)