题目链接
Atcoder方向
Luogu方向
题目解法
首先需要得到一个性质:
当
X
i
≠
X
j
Xi\ne Xj
Xi=Xj 时,
i
,
j
i,j
i,j 操作的先后顺序可以交换
证明:
可以画一张图,只考虑
Y
i
=
Y
j
=
0
Yi=Yj=0
Yi=Yj=0 的情况,其他情况也可以推出
下面是只考虑
X
i
,
X
j
Xi,Xj
Xi,Xj 位
0
,
1
0,1
0,1 的情况:
考虑交换绿色与红色边的贡献顺序,实际上每个点被贡献到的值是不变的
所以可以将操作按
X
i
Xi
Xi 分开做(注意,
X
i
Xi
Xi相同的不满足交换律)
现在只需要考虑第
i
i
i 位的贡献
考虑每次贡献只会在 2 个中进行,即有
2
n
−
1
2^{n-1}
2n−1 组,只需要考虑每组中的贡献
令一组中第
i
i
i 位为
0
0
0 的为
a
i
a_i
ai,第
i
i
i 位为
1
1
1 的为
a
j
a_j
aj
那么
a
i
′
=
p
0
∗
a
i
+
p
1
∗
a
j
a_i'=p0*a_i+p1*a_j
ai′=p0∗ai+p1∗aj,
a
j
′
=
q
0
∗
a
i
+
q
1
∗
a
j
a_j'=q0*a_i+q1*a_j
aj′=q0∗ai+q1∗aj
考虑求出
p
0
,
p
1
,
q
0
,
q
1
p0,p1,q0,q1
p0,p1,q0,q1 即可以算出答案
时间复杂度 O ( n ∗ 2 n ) O(n*2^n) O(n∗2n)
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N(20),P(998244353);
int n,q,a[1<<N],b[1<<N];
vector<int> op[N];
inline int read(){
int FF=0,RR=1;
char ch=getchar();
for(;!isdigit(ch);ch=getchar()) if(ch=='-') RR=-1;
for(;isdigit(ch);ch=getchar()) FF=(FF<<1)+(FF<<3)+ch-48;
return FF*RR;
}
int main(){
n=read(),q=read();
for(int i=0;i<1<<n;i++) a[i]=read();
for(int i=1,x,y;i<=q;i++) x=read(),y=read(),op[x].push_back(y);
for(int i=0;i<n;i++){
int x0=1,y0=0,x1=0,y1=1;
for(int j=0;j<op[i].size();j++){
int t=op[i][j];
if(!t) (x1+=x0)%=P,(y1+=y0)%=P;
else (x0+=x1)%=P,(y0+=y1)%=P;
}
for(int j=0;j<1<<n;j++){
int k=j^(1<<i);
if(j>>i&1) b[j]=((LL)x1*a[k]%P+(LL)y1*a[j]%P)%P;
else b[j]=((LL)x0*a[j]%P+(LL)y0*a[k]%P)%P;
}
for(int j=0;j<1<<n;j++) a[j]=b[j];
}
for(int i=0;i<1<<n;i++) printf("%d ",a[i]);
return 0;
}