Description
Solution
假设 选择的是集合 , 选择的是集合 。
观察到条件:
以及
我们考虑枚举 ,因为 的元素异或和为 ,并且每找到一个元素异或和为 的非空集合 ,我们有 种方法拆分它为 和 。
构造集合幂级数,考虑每个元素选与不选,则问题转化为求下式的值
异或卷积自然考虑用 做一做。
里面相当于要做 次 ,复杂度有点离谱。
考虑一个奇怪的事情:事实上,我们每次都只对一个形如 的形式幂级数做 。我们考虑 次 并点乘之后某一项 的值,可以发现
其中的 我们并不知道(只能 求一个),但是最后的值一定是这个形式。
我们发现,如果把上式中的 换成 ,那么有:
众所周知:
于是我们可以先求出 , 然后把每个 的 解出来,那么真实的 我们也可以算出来了,对应位置分别算出来后再 回去即可。
复杂度 。
Code
#include <bits/stdc++.h>
class Input{
private:
char buf[1000000], *p1, *p2;
public:
inline char getc(){
if(p1 == p2) p2 = (p1 = buf) + fread(buf, 1, 1000000, stdin);
return p1 == p2 ? EOF : *(p1++);
}
template<typename tp>inline Input& operator >> (tp &n){
n = 0; char c = getc();
while(!isdigit(c)) c = getc();
while( isdigit(c)) n = n * 10 + c - 48, c = getc();
return (*this);
}
}fin;
const int N = (1 << 20) + 55, mod = 998244353;
using namespace std;
int n;
int a[N], F[N];
long long inv2 = (mod + 1) / 2, inv4 = inv2 * inv2 % mod;
void FWT(int *a, int len, long long tp){
for(int i = 1; i < len; i <<= 1)
for(int j = 0; j < len; j += (i << 1))
for(int k = j; k < i + j; ++k){
int x = a[k], y = a[k + i];
a[k] = tp * (x + y) % mod;
a[i + k] = tp * (x + mod - y) % mod;
}
}
int qpow(long long b, int t){
long long ret = 1;
for(; t; t >>= 1, b = b * b % mod)
if(t & 1) ret = ret * b % mod;
return ret;
}
int main(){
fin >> n;
for(int i = 1; i <= n; ++i)
fin >> a[i], F[a[i]] += 2;
F[0] += n;
int m = 1e6, len = 1;
while(len <= m)
len <<= 1;
FWT(F, len, 1);
for(int i = 0; i < len; ++i){
int t = inv4 * (F[i] + n) % mod;
F[i] = 1ll * qpow(3, t) * qpow(mod - 1, n - t) % mod;
}
FWT(F, len, inv2);
cout << (F[0] + mod - 1) % mod << endl;
return 0;
}