纪念逝去的 40pts
提供一种好想的优化方法。先拿出柿子(这里的 dfs(n, k)
相当于题解的 ):
int dfs(int n, int k) {
if (n == k) return 0;
if (n == 1) return 0;
if (k == 1) return 0;
if (~f[n][k]) return f[n][k];
return f[n][k] = (dfs(n - 1, k) + dfs(n - 1, k - 1) + (n - k + 1 <= k)) % mod;
}
每次答案是 C(n, k) - dfs(n, k)
。考虑一个 数对对答案的贡献,只有在 时,它会贡献 ,并依次往上记录到答案中。这个东西和组合数的递推方式非常像,此时 dfs(n, k)
计算中就会包含 个 数对,这就是它的贡献。
for (int i = 2; i <= n; i++)
for (int j = max(k - n + i, i + 2 >> 1); j <= min(i - 1, k); j++)
(ans += C(n - i, k - j)) %= mod; // k - n + i & k 的限制是为了 n - i >= k - j >= 0
然后你可以得到这样的东西来计算 dfs(n, k)
。然后我们固定一下 ,能贡献它的 是一段区间,可以使用变上限求和 来快速计算。
namespace liuzimingc {
#define pii pair<int, int>
#define endl '\n'
const int maxn = 1e7 + 5, mod = 998244353;
int T, n, k;
long long fac[maxn], inv[maxn];
int qkpow(long long a, int b) {
long long ans = 1;
while (b) {
if (b & 1) ans = ans * a % mod;
a = a * a % mod;
b >>= 1;
}
return ans;
}
int C(int n, int m) {
if (n < m) return 0;
return fac[n] * inv[m] % mod * inv[n - m] % mod;
}
int get(int n, int k) {
return C(n + 1, k + 1);
}
int get_sum(int l, int r, int k) {
return (get(r, k) - get(l - 1, k) + mod) % mod;
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
fac[0] = 1;
for (int i = 1; i <= 10000001; i++) fac[i] = fac[i - 1] * i % mod;
inv[10000001] = qkpow(fac[10000001], mod - 2);
for (int i = 10000000; ~i; i--) inv[i] = inv[i + 1] * (i + 1) % mod;
cin >> T;
while (T--) {
cin >> n >> k;
int ans = 0;
for (int x = 0; x <= k; x++) {
int j = k - x;
int l = n - min(j + n - k, 2 * j - 1), r = n - (j + 1);
if (l <= r) (ans += get_sum(l, r, x)) %= mod;
}
cout << (C(n, k) - ans + mod) % mod << endl;
}
return 0;
}
#undef int
}
Posted by liuzimingc
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY