[CF165E]Compatible Numbers

[CF165E]Compatible Numbers

一.前言

强忍着调了一下午lemon、疯狂卡常失败的病痛,来水了一道……题目链接

二.思路

​ 这题翻译的很明确了,就直接来。

​ 给出的例子是90(1011010)与36(100100)相容,他们&起来等于0.那么简化为 (A&B=0),可以有一个很显然的结论:从 A (B也行)中任意位上取走一个1,得到的 A'&B=0. 十分显然的性质。因为在一位上的两个数&=0,只有两个0和一个1一个0两种情况,很显然取走一个1就是将第一个情况变成第二个。

​ 但是此时依旧没有得到和答案有关的结论,没关系。

​ 设 ans[i] 为在数列中 &i 为0的,由上面的结论可以得出若 (j|i==0,j<i,ans[j]=ans[i]).那么就可以转移了奥。首先初始化为-1,我们最好选择由大转移到小的。对于一个在数列中的值 k ,求使得 (ans[p]=k),的p的最大值,显而易见的,(p=sim k&inf),(inf为很多个1连在一起,~为按位取反,可以手玩感受一下)

​ 那么在读入的时候就计算出 p,然后从inf依次扫描,若 (ans[i]!=-1) 则用 i 对若干个 j(由i取一个1得到)进行转移就好。

​ 最后提一点,(inf=(1<<22)-1) ,是因为(log_2(4*10^8)approx22)

三.CODE

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<fstream>
#include<cmath>
#include<cstring>
using namespace std;
int read(){
	char ch=getchar();
	int res=0,f=1;
	for(;ch<'0'||ch>'9';ch=getchar())if(ch=='-')f=-1;
	for(;ch>='0'&&ch<='9';ch=getchar())res=res*10+(ch-'0');
	return res*f;
}
const int inf=(1<<22)-1;
int n,a[inf+1],ans[inf+1];
int main(){
	memset(ans,-1,sizeof(ans));
	n=read();
	for(int i=1;i<=n;++i){
		a[i]=read();
		ans[~a[i]&inf]=a[i];
	}
	for(int i=inf;i>0;--i){
		if(ans[i]!=-1){
			for(int j=0;j<=21;++j){
				if(i&(1<<j)){
					ans[i-(1<<j)]=ans[i];
				}
			}
		}
	}
	for(int i=1;i<=n;++i)cout<<ans[a[i]]<<" ";
	return 0;
}
原文地址:https://www.cnblogs.com/clockwhite/p/13399274.html