codeforces 165E. Compatible Numbers

高维前缀和

题目传送门

学了一发高维前缀和。

一般我们求多维前缀和是用容斥的,但是当维度很高时会很烦,这时就要用另一种求前缀和的方法。

打个比方,假设我们要求二维前缀和:

for (int i=1;i<=n;i++)
    for (int j=1;j<=m;j++)
        a[i][j]+=a[i][j-1];
for (int i=1;i<=n;i++)
    for (int j=1;j<=m;j++)
        a[i][j]+=a[i-1][j];

这样就很好写了。而高维前缀和可以解决关于子集和超集统计的问题(复杂度为 O ( n ∗ 2 n ) O(n*2^n) O(n2n),而枚举子集的复杂度为 O ( 3 n ) O(3^n) O(3n)),只要把每一位看作一维进行操作就好了。

对于这道题,当 a &amp; b = 0 a\&amp;b=0 a&b=0时, a a a取反后是 b b b的超集,反之亦然。那么只需要做一遍高维前缀和就可以求出任意一个超集了。

代码:

#include<cctype>
#include<cstdio> 
#include<cstring>
#include<algorithm>
#define N 1000005
#define F inline
using namespace std;
int n,a[N],s[1<<22];
F char readc(){
	static char buf[100000],*l=buf,*r=buf;
	if (l==r) r=(l=buf)+fread(buf,1,100000,stdin);
	return l==r?EOF:*l++;
}
F int _read(){
	int x=0; char ch=readc();
	while (!isdigit(ch)) ch=readc();
	while (isdigit(ch)) x=(x<<3)+(x<<1)+(ch^48),ch=readc();
	return x;
}
int main(){
	n=_read();
	for (int i=1;i<=n;i++) a[i]=_read(),s[~a[i]&(1<<22)-1]=a[i];
	for (int i=0;i<22;i++)
		for (int j=0;j<1<<22;j++)
			if (!(j>>i&1)&&s[j|1<<i]) s[j]=s[j|1<<i];
	for (int i=1;i<=n;i++)
		printf("%d ",s[a[i]]?s[a[i]]:-1);
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值