QOJ 5019 整数
考虑从低位向高位 dp,设 \(f_{i, S}\) 为考虑到从低到高第 \(i\) 位,当前每个数超出上界的情况为 \(S\)。
转移可以枚举这一位填的数:
- 若 \(a_j = 0, r_j = 1\),那么这一位一定不会超出上界;
- 若 \(a_j = 1, r_j = 0\),那么这一位一定会超出上界。
- 否则情况和之前相同。
容易发现,若 \(r_j = 1\),相当于做按位与,否则是按位或。做 FWT 即可。
code
#include <bits/stdc++.h>
#define pb emplace_back
#define fst first
#define scd second
#define mkp make_pair
#define mems(a, x) memset((a), (x), sizeof(a))
using namespace std;
typedef long long ll;
typedef double db;
typedef unsigned long long ull;
typedef long double ldb;
typedef pair<ll, ll> pii;
const int maxn = 20;
const int maxm = (1 << 18) + 50;
const ll mod = 998244353;
ll c[maxn];
int f[maxm], g[maxm], h[maxm], n, m, b[maxm];
inline void upd(int &x, int y) {
((x += y) >= mod) && (x -= mod);
}
inline void FWT(int *a, int op, int d) {
for (int k = 1, t = 0; k < m; k <<= 1, ++t) {
for (int i = 0; i < m; i += (k << 1)) {
for (int j = 0; j < k; ++j) {
if (c[t] & (1LL << d)) {
upd(a[i + j], op == 1 ? a[i + j + k] : mod - a[i + j + k]);
} else {
upd(a[i + j + k], op == 1 ? a[i + j] : mod - a[i + j]);
}
}
}
}
}
void solve() {
scanf("%d", &n);
for (int i = 0; i < n; ++i) {
scanf("%lld", &c[i]);
}
m = (1 << n);
for (int i = 0, x; i < m; ++i) {
scanf("%1d", &x);
b[i] = x;
}
h[0] = 1;
for (int d = 0; d < 60; ++d) {
for (int i = 0; i < m; ++i) {
f[i] = h[i];
g[i] = b[i];
}
FWT(f, 1, d);
FWT(g, 1, d);
for (int i = 0; i < m; ++i) {
f[i] = 1LL * f[i] * g[i] % mod;
}
FWT(f, -1, d);
for (int i = 0; i < m; ++i) {
h[i] = f[i];
}
}
printf("%d\n", h[0]);
}
int main() {
int T = 1;
// scanf("%d", &T);
while (T--) {
solve();
}
return 0;
}