【Atcoder】 [ARC151D] Binary Representations and Queries

文章详细介绍了针对特定编程竞赛(Atcoder和Luogu)中的一类问题的解决方案,涉及二进制位的操作。解题策略是基于操作顺序的可交换性,通过分离不同位的处理,并计算每位置的贡献,最终得出时间复杂度为O(n*2^n)的方法。
摘要由CSDN通过智能技术生成

题目链接

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} 2n1 组,只需要考虑每组中的贡献
令一组中第 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=p0ai+p1aj a j ′ = q 0 ∗ a i + q 1 ∗ a j a_j'=q0*a_i+q1*a_j aj=q0ai+q1aj
考虑求出 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(n2n)

#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;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值