分析
设多项式
A
=
∑
i
=
0
2
n
−
1
a
i
x
i
,
B
=
∑
i
=
0
2
n
−
1
b
i
x
i
A=\sum\limits_{i=0}^{2^n-1}a_ix^i,B=\sum\limits_{i=0}^{2^n-1}b_ix^i
A=i=0∑2n−1aixi,B=i=0∑2n−1bixi
求
C
=
A
∗
B
=
∑
i
=
0
2
n
−
1
x
i
∑
d
⊆
i
a
d
b
i
−
d
C=A*B=\sum\limits_{i=0}^{2^n-1}x^i\sum\limits_{d \subseteq i}a_d b_{i-d}
C=A∗B=i=0∑2n−1xid⊆i∑adbi−d可以用
O
(
n
2
2
n
)
O(n^22^n)
O(n22n)来完成
具体就是按照每个状态的最高位进行分组,然后卷n次,这样的复杂度计算是
O
(
∑
i
=
1
n
i
2
2
i
)
=
O
(
n
2
2
n
)
O(\sum\limits_{i=1}^{n}i^22^i) = O(n^22^n)
O(i=1∑ni22i)=O(n22n)
代码
#include <bits/stdc++.h>
#define rep(i,a,b) for(int i=(a);i<=(b);++i)
#define dep(i,a,b) for(int i=(a);i>=(b);--i)
#define MP make_pair
#define fi first
#define se second
#define PB push_back
#define CL clear
#define pii pair<int,int>
// #define int long long
using namespace std;
mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());
const int N = (int)(1e6) + 10;
const int mod = 998244353;
const int inf = 1e9;
inline int rd() {
int p=0; int f=1; char ch=getchar();
while(ch<'0' || ch>'9'){if(ch=='-') f=-1; ch=getchar();}
while(ch>='0' && ch<='9'){p=p*10+ch-'0'; ch=getchar();}
return p*f;
}
struct node{int p,b;}w[N];
bool cmp(const node &x,const node &y){return x.b<y.b;}
int a[22][(1<<21)+1],b[22][(1<<21)+1],c[(1<<21)+1];
void FMT(int *a,int n,int op) {
for(int l=0;(1ll<<l)<n;++l)
for(int i=0;i<n;++i)
if(i&(1ll<<l)) a[i] = (1ll * a[i] + 1ll * op * a[i^(1ll<<l)] + mod) % mod;
}
int ans[(1<<21)+1];
signed main() {
int n = rd();
rep(i,1,n) w[i].p = rd(),w[i].b = rd();
sort(w+1,w+n+1,cmp); int j = 1;
while(w[j].b < 2 && j<=n) (a[__builtin_popcount(w[j].b)][w[j].b] += w[j].p) %= mod,j++; a[0][0] = 1; ans[1] = a[1][1];
rep(i,2,21) {
b[0][0] = 1; while(w[j].b < (1ll<<i) && j<=n) {
(b[__builtin_popcount(w[j].b)][w[j].b] += w[j].p) %= mod;
j++;
}
for(int k=0;k<=i;k++) FMT(a[k],(1ll<<i),1),FMT(b[k],(1ll<<i),1);
for(int k1=i;k1>=0;k1--) {
for(int k2=0;k2<=k1;k2++) for(int p=0;p<(1ll<<i);p++) {
c[p] = (1ll * c[p] + 1ll * a[k2][p] * b[k1-k2][p]) % mod;
}
FMT(c,(1<<i),-1);
memcpy(a[k1],c,sizeof(c));
for(int p=0;p<(1ll<<i);p++) c[p] = 0;
}
for(int k=(1ll<<(i-1));k<(1ll<<i);k++) ans[k] = (ans[k] + a[__builtin_popcount(k)][k]) % mod;
for(int k=0;k<=i;k++) for(int p=0;p<(1ll<<i);p++) b[k][p] = 0;
}
int q = rd(); while(q--){int x=rd(); printf("%d\n",ans[x]);}
return 0;
}