题解:AT_arc205_e [ARC205E] Subset Product Problem
___PatrickChen___ · · 题解
前置芝士:值域分块、少量集合论(主要是为了方便表示)。
以下我们将数以二进制形式表示为一个集合。 即:
若一个数二进制表示为
由于符号
\subset 存在歧义,下文用\subseteq 表示“包含于”,\subsetneq 表示“真包含于”。
根据以上形式,题目要求的可以转化为以下形式:
我们将每一个
下面我们进行值域分块。我们考虑依据
接下来我们考虑如何维护每一个块的信息。记
接下来我们只需要实现插入操作和查询操作就可以求出答案了。
我们进行插入
进行查询操作的时候,我们查询满足条件的块,即枚举满足
插入和查询复杂度均为
最后注意除了左移右移以外的位运算(或、与、异或)优先级小于逻辑符号,需要括号。
code:
#include <bits/stdc++.h>
#define endl '\n'
using namespace std;
using ll = long long;
const ll N = 5e4 + 5, M = 1 << 10, P = 998244353;
int n;
ll f[M][M];// 分块数组
void init() {}
void solve()
{
cin >> n;
// 初始化
for (int i = 0; i < 1 << 10; ++i)
{
for (int j = 0; j < 1 << 10; ++j)
f[i][j] = 1;
}
for (int i = 1; i <= n; ++i)
{
ll x, p, q, res = 1;
cin >> x;
// 拆位
p = x >> 10;
q = x & ((1 << 10) - 1);
// 插入,枚举 p 的超集
for (int j = 0; j < 1 << 10; ++j)
{
if ((p | j) == j)
(f[j][q] *= x) %= P;
}
// 查询,枚举 q 的子集
for (int j = 0; j < 1 << 10; ++j)
{
if ((j | q) == q)
(res *= f[p][j]) %= P;
}
cout << res << endl;
}
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);
int _ = 1;
// cin >> _;
init();
while (_--)
solve();
return 0;
}