[Solution] October 18, 2017
截至目前题解区均采用生成函数方式解决该问题,此处提供官方题解的组合意义做法。
这个做法很难想到,且需灵活运用部分线性代数知识,鄙人对着官解看了两天才终于看懂。官解式子的上下标似乎有点细节问题。
\text{Task}
题目链接:October 18, 2017。
在线性空间
\text{Solution}
当
当
前置知识:正交补空间。
前置结论:
- 若
V 是\mathbb{F}_q 上的n 维线性空间,则V 有\dfrac{q^n-1}{q-1} 个n-1 维线性子空间。 - 若
V 是\mathbb{F}_q 上的n 维线性空间,\vec{x}\in V\backslash\{0\} ,则V 有\dfrac{q^{n-1}-1}{q-1} 个线性子空间包含\vec{x} 。
以上结论读者不难自证可以自行查询相关证明。(因为证明部分我没太看懂。)
假设向量
也就是说,统计形如
由于
综上,答案式如下(累乘符号下标大于上标时值视为
因为刨除向量
容易感性理解到以上式子是正确的,但在后半部分依然附上证明。
考虑证明以上容斥恰好将每个向量组
经过尝试发现,直接通过
当正交补空间包含向量
此时多元组数量的统计与前文是相同的,乘上前文统计时的容斥系数,因此只需证明以下式子成立(累乘符号下标大于上标时值视为
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 1e7+5;
const int MOD = 998244353;
int T, n, k, x;
int pw[N], d[N], g[N];
int qmont(int x, int k) {
int rst = 1;
while (k) {
if (k & 1) rst = (LL)rst*x%MOD;
x = (LL)x*x%MOD;
k >>= 1;
}
return rst;
}
int main() {
pw[0] = 1;
for (int i = 1; i < N; i++) pw[i] = pw[i-1]*2%MOD;
scanf("%d", &T);
while (T--) {
scanf("%d%d%d", &n, &k, &x);
if (!x) {
if (!k || n > k) printf("%d\n", 0);
else {
int rst = 1;
for (int i = 0; i < n; i++)
rst = (LL)rst*(pw[k]-pw[i]+MOD)%MOD;
printf("%d\n", rst);
}
} else {
if (!k) printf("%d\n", 1);
else {
d[k] = 1;
for (int i = k-1; i >= 0; i--) {
g[i] = (LL)pw[i]*d[i+1]%MOD;
d[i] = (LL)(pw[i]-1+MOD)*d[i+1]%MOD;
}
int rst = 0, now = 1, p = qmont(2, n);
for (int i = 0; i < k; i++) {
rst += (LL)((k-i-1)&1 ? MOD-1 : 1)*g[i]%MOD*now%MOD;
(rst >= MOD) && (rst -= MOD);
now = (LL)now*p%MOD;
}
printf("%d\n", rst);
}
}
}
return 0;
}