高维前缀和-CF165E Compatible Numbers题解

CF165E Compatible Numbers

题面:

题面翻译

有两个整数a,b。如果a&b=0,那么我们称a与b是相容的。比如90(1011010)与36(100100)相容。给出一个序列aa ,你的任务是对于每个ai,找到在序列中与之相容的aj 。如果找不到这样的数,输出-1。
贡献者:An_Account

1 ≤ n ≤ 1 0 6 , 1 ≤ a i ≤ 4 × 1 0 6 1 \leq n \leq 10^6,1\leq a_i \leq 4\times 10^6 1n106,1ai4×106

题目描述

Two integers $ x $ and $ y $ are compatible, if the result of their bitwise “AND” equals zero, that is, $ a $ $ & $ $ b=0 $ . For example, numbers $ 90 $ $ (1011010_{2}) $ and $ 36 $ $ (100100_{2}) $ are compatible, as $ 1011010_{2} $ $ & $ $ 100100_{2}=0_{2} $ , and numbers $ 3 $ $ (11_{2}) $ and $ 6 $ $ (110_{2}) $ are not compatible, as $ 11_{2} $ $ & $ $ 110_{2}=10_{2} $ .

You are given an array of integers $ a_{1},a_{2},…,a_{n} $ . Your task is to find the following for each array element: is this element compatible with some other element from the given array? If the answer to this question is positive, then you also should find any suitable element.

输入格式

The first line contains an integer $ n $ ( $ 1<=n<=10^{6} $ ) — the number of elements in the given array. The second line contains $ n $ space-separated integers $ a_{1},a_{2},…,a_{n} $ ( $ 1<=a_{i}<=4·10^{6} $ ) — the elements of the given array. The numbers in the array can coincide.

输出格式

Print $ n $ integers $ ans_{i} $ . If $ a_{i} $ isn’t compatible with any other element of the given array $ a_{1},a_{2},…,a_{n} $ , then $ ans_{i} $ should be equal to -1. Otherwise $ ans_{i} $ is any such number, that $ a_{i} $ $ & $ $ ans_{i}=0 $ , and also $ ans_{i} $ occurs in the array $ a_{1},a_{2},…,a_{n} $ .

样例 #1
样例输入 #1
2
90 36
样例输出 #1
36 90
样例 #2
样例输入 #2
4
3 6 3 6
样例输出 #2
-1 -1 -1 -1
样例 #3
样例输入 #3
5
10 6 9 8 2
样例输出 #3
-1 8 2 2 8

高维前缀和!

简单的说,普通的前缀和( 1 ∼ 3 1\sim 3 13 维),我们经常使用容斥

但是,维度一高,容斥的复杂度大的吓人!

我们得换一种全新的方法!————高维前缀和 闪亮登场!

我们不妨来考虑这样一个事情:

我们的终极目标是把 1 ≤ i ≤ x , 1 ≤ j ≤ y , … 1\leq i \leq x,1\leq j \leq y,\ldots 1ix,1jy, 上的所有点累加到 ( x , y , … ) (x,y,\ldots) (x,y,)

那么,我们可以像著名游戏 2048 那样,每次直接搞定一个维度,将所有维度搞定之后,前缀和就做完了

以二维举例:
假设我们的原数组是这样的:
img

我们对 x x x 维先做一个前缀和:
img

然后再对 y y y 维做一个前缀和:
img

我们再举一个例子,加深印象:
img

x − T r a n s f o r m : x-Transform: xTransform:
img

y − T r a n s f o r m : y-Transform: yTransform:
img

回到正题,高维前缀和和这个有什么关系呢?

高维前缀和还有子集求和的功能!

对于一个 S ( 2 ) \mathbf{S}(2) S(2) 01 01 01 串,我们让 f S = ∑ S ′ ∈ S a S ′ f_{\mathbf{S}} = \sum_{\mathbf{S^\prime} \in \mathbf{S}} a_{\mathbf{S^\prime}} fS=SSaS

根据高维前缀和的搞法,可以得到
f S = ∑ i ∈ S f S ⊕ 2 i f_{\mathbf{S}} = \sum_{i \in \mathbf{S}} f_{\mathbf{S}\oplus 2^i} fS=iSfS2i

这道题,我们发现, a & b = 0 ⇔ b ⊆ ( a ⊕ U ) a\And b = 0 \Leftrightarrow b \subseteq (a \oplus U) a&b=0b(aU)

那么,对于一个数,我们只需要找到ta补集子集中可行的的一个答案就可以了

对于一个数 s s s,我们将 f s = s f_s = s fs=s;

我们将 1 ∼ 2 22 ( 4 × 1 0 6 ≤ 2 22 ≤ 5 × 1 0 6 ) 1 \sim 2^{22}(4\times 10^6 \leq 2^{22} \leq 5\times 10^6) 1222(4×1062225×106) f i f_i fi 做一次"高维前缀和"(非狭义中的和,指保存可能的答案之一)

最后对询问 a a a,访问 U ⊕ a \mathbf{U} \oplus a Ua 子集中是否有答案即可!

AC-code:

#include<bits/stdc++.h>
using namespace std;
#define int long long		
int rd() {
	int x = 0, w = 1;
	char ch = 0;
	while (ch < '0' || ch > '9') {
		if (ch == '-') w = -1;
		ch = getchar();
	}
	while (ch >= '0' && ch <= '9') {
		x = x * 10 + (ch - '0');
		ch = getchar();
	}
	return x * w;
}

void wt(int x) {
	static int sta[35];
	int f = 1;
	if(x < 0) f = -1,x *= f;
	int top = 0;
	do {
		sta[top++] = x % 10, x /= 10;
	} while (x);
	if(f == -1) putchar('-');
	while (top) putchar(sta[--top] + 48);
}
const int N = 1e6+5,M = 5e6+5,U = (1 << 22) - 1;
int a[N],f[M],n;

signed main() {
	n = rd();
	for(int i = 1;i<=n;i++) {
		a[i] = rd();
		f[a[i]] = a[i];
	}

	for(int i = 0;i<=21;i++)
		for(int j = 0;j<(1<<22);j++) 
			if((j & (1 << i)) && f[j ^ (1 << i)]) 
				f[j] = f[j ^ (1<<i)];
	for(int i = 1;i<=n;i++) {
		int b = U ^ a[i];
		wt(f[b] ? f[b] : -1);putchar(' ');
	}
	
	return 0;
}

这种东西叫做 S O S   d p SOS\ dp SOS dp 高维前缀和-动态规划

本博客:
  监督:MingJunYi
  超监督:凉宫春日


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值