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