Codeforces 165E Compatible Numbers 【dp】

题目链接:Codeforces 165E Compatible Numbers

E. Compatible Numbers
time limit per test4 seconds
memory limit per test256 megabytes
inputstandard input
outputstandard output
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 (10110102) and 36 (1001002) are compatible, as 10110102 & 1001002 = 02, and numbers 3 (112) and 6 (1102) are not compatible, as 112 & 1102 = 102.

You are given an array of integers a1, a2, …, an. 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.

Input
The first line contains an integer n (1 ≤ n ≤ 106) — the number of elements in the given array. The second line contains n space-separated integers a1, a2, …, an (1 ≤ ai ≤ 4·106) — the elements of the given array. The numbers in the array can coincide.

Output
Print n integers ansi. If ai isn’t compatible with any other element of the given array a1, a2, …, an, then ansi should be equal to -1. Otherwise ansi is any such number, that ai & ansi = 0, and also ansi occurs in the array a1, a2, …, an.

Examples
input
2
90 36
output
36 90
input
4
3 6 3 6
output
-1 -1 -1 -1
input
5
10 6 9 8 2
output
-1 8 2 2 8

题意:有n个数,让你找到一个任意a[j]使得 a[j] & a[i] == 0,不存在输出-1。

思路:考虑dp。
我们发现对于二进制10101来说,它的合法结果一定是10001、00101、10100的合法结果。也就是说对于一个数i来讲,我们去掉i的二进制中任意一个1得到的数k,i的合法结果一定是k的合法结果。

最大的数为(1<<22),记 N= 1<<22 - 1。
设置dp[i]为i的一个集合,也就是说对于集合中任意一个元素T,总会满足T & (N ^ i) == 0。那么 dp[i]=dp[i(2j)](1<=(2j)<=N) 。题目只要求一个解,我们只记录一个就可以了。
对于a[i]的结果我们要找到一个T使得 T & (N ^ N ^ a[i]) == 0,显然结果为dp[N ^ a[i]]。

AC代码:

#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <cstring>
#include <queue>
#include <set>
#define CLR(a, b) memset(a, (b), sizeof(a))
#define fi first
#define se second
#define ALL(x) x.begin(), x.end()
#define INS(x) inserter(x, x.begin())
using namespace std;
typedef long long LL;
typedef pair<int, int> pii;
const int MAXN = 1e6 +10;
const int INF = 0x3f3f3f3f;
const int MOD = 1e9 + 7;
void add(LL &x, LL y) { x += y; x %= MOD; }
int a[MAXN];
//set<int> ans[MAXN], bit[30];
//bool vis[1<<22];
int dp[1<<22];
int main()
{
    int n;
    while(scanf("%d", &n) != EOF) {
        for(int i = 0; i < (1<<22); i++) dp[i] = -1;
        for(int i = 1; i <= n; i++) {
            scanf("%d", &a[i]);
            //vis[a[i]] = true;
            dp[a[i]] = a[i];
        }
        int N = (1<<22);
        for(int i = 0; i < N; i++) {
            if(dp[i] == -1) {
                for(int j = 0; j <= 22; j++) {
                    if(i & (1<<j) && dp[i ^ (1<<j)] != -1) {
                        dp[i] = dp[i ^ (1<<j)];
                    }
                }
            }
        }
        for(int i = 1; i <= n; i++) {
            if(i > 1) printf(" ");
            printf("%d", dp[(N-1) ^ a[i]]);
        }
        printf("\n");
    }
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值