結果
問題 |
No.1696 Nonnil
|
ユーザー |
|
提出日時 | 2025-08-05 23:54:13 |
言語 | PyPy3 (7.3.15) |
結果 |
AC
|
実行時間 | 223 ms / 3,500 ms |
コード長 | 1,831 bytes |
コンパイル時間 | 179 ms |
コンパイル使用メモリ | 82,168 KB |
実行使用メモリ | 92,368 KB |
最終ジャッジ日時 | 2025-08-05 23:54:23 |
合計ジャッジ時間 | 6,781 ms |
ジャッジサーバーID (参考情報) |
judge5 / judge2 |
(要ログイン)
ファイルパターン | 結果 |
---|---|
sample | AC * 4 |
other | AC * 39 |
ソースコード
import sys input = lambda: sys.stdin.readline().rstrip() mod = 998244353 INF = 10**18 # 1. 读入 n, k, m n, k = map(int, input().split()) # n: 序列长度, k: 值域上界 m = int(input()) # 区间个数 # 2. 预处理每个起点 i 最晚要打点的位置 g[i] g = [INF]*k for _ in range(m): l, r = map(int, input().split()) l -= 1 if r < g[l]: g[l] = r # 从右往左做一个前缀最小化 for i in range(k-2, -1, -1): if g[i+1] < g[i]: g[i] = g[i+1] # 3. 初始化 dp 和前缀和 sumv # dp[j][r] = 选了 j 个点,最后一个打在 r 的方案数 dp = [[0]*(k+1) for _ in range(k+1)] sumv = [0]*(k+1) dp[0][0] = 1 # 还没开始就选了 0 个点,算 1 种 sumv[0] = 1 # 4. 逐个位置 i(对应 C++ 里 0..k-1) for i in range(k): # 如果 g[i] != INF,强制在 [i, g[i]) 之间至少打一个点 if g[i] != INF: for j in range(k+1): # 把所有还没在 [i, g[i]) 打点的方案扣掉 dp[j][g[i]] = (dp[j][g[i]] - sumv[j]) % mod sumv[j] = 0 # 普通的“选 / 不选”转移 for j in range(k-1, -1, -1): v = dp[j][i] # 当前位置 i, 已打 j 个点的方案数 # 如果在 i 打第 j+1 个点 sumv[j+1] = (sumv[j+1] + v) % mod # 如果不在 i 打,保持 j 个点 sumv[j] = (sumv[j] - v) % mod # 状态从 dp[j][i] 迁移到 dp[j+1][i+1] dp[j+1][i+1] = (dp[j+1][i+1] + v) % mod # 清空旧状态 dp[j][i] = 0 # 5. 把“打了 i 个点的方案数” 转成 “序列数” 并累加 res = 0 for i in range(k+1): # dp[i][k] 就是选了 i 个点且走完所有位置的方案数 cnt = dp[i][k] # i^n % mod pw = pow(i, n, mod) res = (res + cnt * pw) % mod # 6. 输出结果 print(res)