Question#
对于一个长度为 的序列 ,我们定义其 AND 数组 如下:
换句话说, 是对序列 中所有长度为 的子序列的元素按位与的和。
序列 对你而言是未知的。但你被提供了一个长度为 的序列 ,满足对所有 ,都有 。你的任务是基于给定的序列 还原序列 。
Solution#
我们设二进制的第 位在数组 中出现了 次,那么对于一个长度为 的子序列,它的 AND 在第 位为 的选法有
种,所以第 位对 的贡献就是
于是
这就是整题的本质。
现在我们要把每个 求出来
倒着枚举 。
因为:
- 如果 ,那么
- 如果 ,那么
- 如果 ,那么它的贡献可以用之前已经知道的 算出来
所以对当前 ,先把所有 的贡献减掉:
那么剩下的就是:
于是我们看 的哪一位为 就代表这一位对应的
现在我们得到了 要构造数组,暴力能放就放就好了
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const ll MOD = 1e9 + 7;
const int MAXN = 1e5 + 5;
ll Fac[MAXN], InvFac[MAXN];
ll pow(ll a, ll b) {
ll res = 1;
while (b) {
if (b & 1) res = res * a % MOD;
a = a * a % MOD;
b >>= 1;
}
return res;
}
void init() {
Fac[0] = 1;
for (int i = 1; i < MAXN; i++) Fac[i] = Fac[i - 1] * i % MOD;
InvFac[MAXN - 1] = pow(Fac[MAXN - 1], MOD - 2);
for (int i = MAXN - 2; i >= 0; i--) InvFac[i] = InvFac[i + 1] * (i + 1) % MOD;
}
ll C(int n, int m) {
if (m > n || m < 0) return 0;
return Fac[n] * InvFac[m] % MOD * InvFac[n - m] % MOD;
}
void solve() {
int n; cin >> n;
vector<ll> b(n + 1);
vector<ll> cnt(29, 0);
for (int i = 1; i <= n; i++) cin >> b[i];
for (int k = n; k >= 1; k--) {
ll val = b[k];
for (int j = 0; j < 29; j++) {
val -= (1LL << j) * C(cnt[j], k) % MOD;
val = (val % MOD + MOD) % MOD;
}
for (int j = 0; j < 29; j++)
if (val >> j & 1) {
cnt[j] = k;
}
}
vector<ll> a(n + 1);
for (int i = n; i >= 1; i--) {
for (int j = 0; j < 29; j++) {
if (cnt[j] > 0) a[i] += 1LL << j, cnt[j]--;
}
}
for (int i = 1; i <= n; i++) cout << a[i] << " \n"[i == n];
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr); cout.tie(nullptr);
init();
int t; cin >> t;
while (t--) solve();
return 0;
}cpp