社论 22.10.7
给定三个正整数 ,求满足以下条件的序列 的个数:
- 对于每一个 ,。
- 序列 没有异或和为 的非空子序列。
答案对 取模。
。
数学题。
转化题意,序列的每个元素等价于 内的一个向量。因此我们需要选出 内的 个向量,满足他们构成的空间内不存在向量 ,求选择方案。分情况讨论:
问题转为选出 内 个线性无关的向量。
这是个经典问题,又可以转化成选出一个满秩的 矩阵的方案数。
答案即为
证明类似这个,这里从略。
可以 地计算答案。
容易发现在 内任意向量等价。因此任意 的答案相同。不妨令 。我们令选出的 个向量与 构成一个 矩阵。
先不考虑dp。直接按组合意义容斥可得答案。
我们考虑不包含 的维度为 的向量空间的基底数量,同上可以得到计算式
然后考虑剩下的 个向量,他们应当被基底表出。考虑第 个向量能表出的向量可以表为 ,于是立得答案为
如果你熟悉 ,那这玩意就等于是 的情况,于是立得
答案即为
如果你不熟悉 ,那就去熟悉
我们考虑表出 。用两种方式消掉 的项得到
两边取 ,经过简单移项可得递推关系式。
然后考虑dp,设 为选了 个向量,当前矩阵的秩为 的方案数。我们考虑新加入的向量是否能被先前除 1 外的向量表出,立即有方程
得到了 的做法。
考虑按第一维求和得到 :
带入 递推式立得 递推式:
答案即为
考虑记
容易发现这是 q
我们承接上面消最低次项的思路得到 ,于是提取系数得
于是这玩意就是一个 ,总贡献得到
转化形式求和得到
可以发现这两种方式得到的答案是相同的。
直接模拟计算即可。预处理后单次计算答案复杂度 。
code
#include <bits/stdc++.h>
#define rep(i,a,b) for (register int (i) = (a); (i) <= (b); ++(i))
#define pre(i,a,b) for (register int (i) = (a); (i) >= (b); --(i))
using namespace std;
const int N = 1e7 + 10, K = 1<<15, mod = 998244353, inv2 = 499122177;
int T, n, k, x, pw[N], upw[K + 10], fac[N], ifac[N];
typedef long long ll; typedef __int128 lll;
struct FastMod { int m; ll b; void init(int _m) { m = _m; b = ((lll)1<<64) / m; } int operator() (ll a) {ll q = ((lll)a * b) >> 64; a -= q * m; if (a >= m) a -= m; return a; } } Mod;
int add(int a, int b) { return (a += b) >= mod ? a - mod : a; } int mul(int a, int b) { return Mod(1ll * a * b); } template <typename ...Args> int mul(int a, Args ...b) { return mul(a, mul(b...)); }
int qp(int a, int b) {
int ret = 1;
while (b) {
if (b & 1) ret = mul(ret, a);
a = mul(a, a);
b >>= 1;
} return ret;
}
void init(int n = N - 10) {
Mod.init(mod);
pw[0] = upw[0] = fac[0] = ifac[0] = 1;
rep(i,1,n) pw[i] = add(pw[i-1], pw[i-1]);
upw[1] = pw[K];
rep(i,2,K) upw[i] = mul(upw[i-1], upw[1]);
rep(i,1,n) fac[i] = mul(fac[i-1], mod + 1 - pw[i]);
ifac[n] = qp(fac[n], mod - 2);
pre(i,n-1,1) ifac[i] = mul(ifac[i+1], mod + 1 - pw[i+1]);
}
int qw(int x) {return mul(upw[x >> 15], pw[x & 32767]);}
int C(int n, int m) {
if (m < 0 or n < m) return 0;
return mul(fac[n], ifac[m], ifac[n-m]);
}
int solve() {
if (x == 0) {
int ret = 1, tmp = min(n-1, k);
if (n > k) return 0;
rep(i,0,n-1) ret = mul(ret, add(pw[k], mod - pw[i]));
return ret;
} else {
int tmp = 1, ans = 0, c = qw(n);
rep(i,0,k-1) {
tmp = mul(tmp, add(c, mod - pw[i]));
ans = add(ans, mul(tmp, C(k-1, i)));
} ans = add(qw(1ll * n * k % (mod - 1)), mod - ans);
return ans;
}
}
signed main() {
ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
cin >> T;
init();
while (T--) {
cin >> n >> k >> x;
cout << solve() << '\n';
}
}
以下是博客签名,与正文无关。
请按如下方式引用此页:
本文作者 joke3579,原文链接:https://www.cnblogs.com/joke3579/p/editorial221007.html。
遵循 CC BY-NC-SA 4.0 协议。
请读者尽量不要在评论区发布与博客内文完全无关的评论,视情况可能删除。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)