loj6358. 前夕
Posted psimonw
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了loj6358. 前夕相关的知识,希望对你有一定的参考价值。
题意
设\(X = \1, 2, \dots, n\\),\(S = 2 ^ X\),求从\(S\)中取出一些集合(可不取),其交集为4的倍数的方案数。
\(n \leq 10 ^ 7\)。
题解
广义容斥 + 构造好题。
设\(g(x)\)表示取出的集合交集数恰好为\(x\)的方案数,\(f(x)\)表示钦定\(x\)个集合一定要取的方案数。
显然,\(f(x) = \binomnx (2 ^ 2 ^ n - x - 1)\),然后\(g(x)\)和\(f(x)\)的关系可以用二项式反演求出,即
\[
g(k) = \sum_i = k ^ n (-1) ^ i - k \binomik f(i)
\]
但是二项式反演所有求\(g(x)\)要\(O(n ^ 2)\)的复杂度。
考虑一种巧妙的构造。
设\(Ans = \sum_i = 0 ^ n f(i) a(i)\)。
由于显然有\(Ans = \sum_i = 0 ^ n g(i) b(i)\),其中\(b(i) = [4 | i]\)。
则
\[
\beginaligned
Ans
& = \sum_k = 0 ^ n [4 | k] \sum_i = k ^ n (-1) ^ i - k \binomik f(i) \& = \sum_i = 0 ^ n f(i) \sum_k = 0 ^ i (-1) ^ i - k \binomik [4|k] \\endaligned
\]
则得出
\[
a(i) = \sum_k = 0 ^ i (-1) ^ i - k \binomik [4|k] \\]
可是还不够,继续。
对于\([4|k]\),用单位根反演,即
\[
[4|k] = \frac14 \sum_i = 0 ^ 3 \omega_4 ^ ik
\]
则
\[
\beginaligned
a(i)
& = \sum_k = 0 ^ i (-1) ^ i - k \binomik \frac14 \sum_l = 0 ^ 3 \omega_4 ^ lk \& = \frac(-1) ^ i4 \sum_k = 0 ^ i (-1) ^ k \binomik \sum_l = 0 ^ 3 (\omega_4 ^ l) ^ k \& = \frac(-1) ^ i4 \sum_l = 0 ^ 3 \sum_k = 0 ^ i \binomik (-1) ^ k (\omega_4 ^ l) ^ k \& = \frac(-1) ^ i4 \sum_l = 0 ^ 3 (1 - \omega_4 ^ l) ^ i \\endaligned
\]
然后这个东西就比较容易了。
直接计算
\[
Ans = 1 + \sum_i = 0 ^ n \binomni (2 ^ 2 ^ n - i - 1) \cdot \frac(-1) ^ i4 \sum_l = 0 ^ 3 (1 - \omega_4 ^ l) ^ i
\]
这个1就是所有集合都不选的方案(注意到它在\(f(0)\)中被除去了)。
处理过程中,是可以用一些技巧,避免使用快速幂的。
所以这个复杂度就是\(\mathcal O(n)\)的,常数为4(实际肯定比这个大很多)。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int power (int a, int b, int mod)
int ret = 1;
for ( ; b; b >>= 1, a = 1ll * a * a % mod)
if (b & 1)
ret = 1ll * ret * a % mod;
return ret;
const int N = 1e7 + 3, mod = 998244353;
const int omega = 911660635, inv4 = 748683265;
int n, ans, f, a, w, r[4], s[4];
int fac[N], ivf[N], po[N], pw[N], pn[N];
int C (int p, int q)
return 1ll * fac[p] * ivf[q] % mod * ivf[p - q] % mod;
void prework ()
fac[0] = ivf[0] = 1;
for (int i = 1; i < N; ++i)
fac[i] = 1ll * fac[i - 1] * i % mod;
ivf[N - 1] = power(fac[N - 1], mod - 2, mod);
for (int i = N - 2; i; --i)
ivf[i] = 1ll * ivf[i + 1] * (i + 1) % mod;
po[0] = 2;
for (int i = 1; i < N; ++i)
po[i] = 1ll * po[i - 1] * po[i - 1] % mod;
w = 1;
for (int i = 0; i < 4; ++i)
r[i] = (1 - w + mod) % mod;
s[i] = 1;
w = 1ll * w * omega % mod;
int main ()
prework();
cin >> n;
for (int i = 0; i <= n; ++i)
f = 1ll * C(n, i) * (po[n - i] - 1 + mod) % mod;
a = 0;
for (int k = 0; k < 4; ++k)
a = (a + s[k]) % mod;
s[k] = 1ll * s[k] * r[k] % mod;
a = 1ll * a * inv4 % mod;
a = i & 1 ? mod - a : a;
ans = (1ll * f * a + ans) % mod;
cout << (ans + 1) % mod << endl;
return 0;
以上是关于loj6358. 前夕的主要内容,如果未能解决你的问题,请参考以下文章