Binary Spiders(2300)trie,位运算,异或和 Codeforces Round #765 (Div. 2)

D. Binary Spiders
time limit per test2 seconds
memory limit per test256 megabytes
inputstandard input
outputstandard output
Binary Spiders are species of spiders that live on Mars. These spiders weave their webs to defend themselves from enemies.

To weave a web, spiders join in pairs. If the first spider in pair has 𝑥 legs, and the second spider has 𝑦 legs, then they weave a web with durability 𝑥⊕𝑦. Here, ⊕ means bitwise XOR.

Binary Spiders live in large groups. You observe a group of 𝑛 spiders, and the 𝑖-th spider has 𝑎𝑖 legs.

When the group is threatened, some of the spiders become defenders. Defenders are chosen in the following way. First, there must be at least two defenders. Second, any pair of defenders must be able to weave a web with durability at least 𝑘. Third, there must be as much defenders as possible.

Scientists have researched the behaviour of Binary Spiders for a long time, and now they have a hypothesis that they can always choose the defenders in an optimal way, satisfying the conditions above. You need to verify this hypothesis on your group of spiders. So, you need to understand how many spiders must become defenders. You are not a Binary Spider, so you decided to use a computer to solve this problem.

Input
The first line contains two integers 𝑛 and 𝑘 (2≤𝑛≤3⋅105, 0≤𝑘≤230−1), the amount of spiders in the group and the minimal allowed durability of a web.

The second line contains 𝑛 integers 𝑎𝑖 (0≤𝑎𝑖≤230−1) — the number of legs the 𝑖-th spider has.

Output
In the first line, print a single integer ℓ (2≤ℓ≤𝑛), the maximum possible amount of defenders.

In the second line, print ℓ integers 𝑏𝑖, separated by a single space (1≤𝑏𝑖≤𝑛) — indices of spiders that will become defenders.

If there exists more than one way to choose the defenders, print any of them.

Unfortunately, it may appear that it’s impossible to choose the defenders. In this case, print a single integer −1.

Examples
inputCopy
6 8
2 8 4 16 10 14
outputCopy
3
1 5 4
inputCopy
6 1024
1 2 3 1 4 0
outputCopy
-1
Note
Consider the examples above.

In the first example, the group of spiders is illustrated on the picture below:

We choose the two-legged, the ten-legged and the 16-legged spiders. It’s not hard to see that each pair may weave a web with enough durability, as 2⊕10=8≥8, 2⊕16=18≥8 and 10⊕16=26≥8.

This is not the only way, as you can also choose, for example, the spiders with indices 3, 4, and 6.

In the second example, no pair of spiders can weave the web with durability 1024 or more, so the answer is −1.

题意 :

  • 给n个数和一个k,要求选出尽可能多的数(至少两个),满足任意两个的异或和都大于等于k,并输出选择的下标;如果不能则输出-1

思路 :

  • 假设k二进制下最高位1为第m位(也就是k的二进制位数);要使得任意两数异或和大于等于k,那么这两个数如果二进制下 m + 1 m+1 m+1 ~ 29位不同,必有异或和大于k,可以任意选;而 m + 1 m+1 m+1 ~ 29位相同的数最多选两个(因为k的第m位必然是1)
  • 因此按照二进制前缀对所有数进行分组,前缀相同为一组,每组中至少可以拿一个数,如果一组中有两个数异或和大于等于k,那么这组可以拿两个数
  • 如何判断一组中是否可以拿两个数呢?也就是我们要快速找到最大的异或和,因此我们用trie(这样就由 n 2 n^2 n2 优化为 n l o g n nlogn nlogn )来维护每一组数,对于每组,最多查找这个组的大小次,只要找到一对,就直接可以查找下一组
  • 注意k为0要特判
#include <iostream>
#include <cstring>
#include <vector>
#include <unordered_map>
#define endl '\n'
using namespace std;

const int N = 3e5 + 10;

int n, m, k;
int a[N];
int tr[N * 30][2], idx;
unordered_map<int, vector<int>> ma;
unordered_map<int, int> id;
vector<int> res;

int bit_size(int x)
{
    int res = 0;
    while (x)
    {
        x >>= 1;
        res ++ ;
    }
    return res;
}

void insert(int x)
{
    int p = 0;
    for (int i = 30; i >= 0; i -- )
    {
        int u = x >> i & 1;
        if (!tr[p][u]) tr[p][u] = ++ idx;
        p = tr[p][u];
    }
}

int query(int x)
{
    int p = 0, res = 0;
    for (int i = 30; i >= 0; i -- )
    {
        int u = x >> i & 1;
        if (!tr[p][!u])
        {
            p = tr[p][u];
            res = res * 2 + u;
        }
        else
        {
            p = tr[p][!u];
            res = res * 2 + !u;
        }
    }
    return res;
}

int main()
{
    cin.tie(0); cout.tie(0); cout.tie(0);
    
    cin >> n >> k;
    m = bit_size(k);
    
    for (int i = 1; i <= n && cin >> a[i]; i ++ )
    {
        int x = (a[i] >> m);
        ma[x].push_back(a[i]);
        id[a[i]] = i;
    }
    
    if (!k)
    {
        cout << n << endl;
        for (int i = 1; i <= n; i ++ ) cout << i << ' ';
        cout << endl;
        return 0;
    }
    
    for (auto it : ma)
    {
        memset(tr, 0, sizeof (int) * 2 * (idx + 1)); idx = 0;
        
        vector<int> ve = it.second;
        
        bool ok = false;
        for (auto x : ve)
        {
            insert(x);
            int t = query(x);
            if ((t ^ x) >= k)
            {
                ok = true;
                res.push_back(id[x]);
                res.push_back(id[t]);
                break;
            }
        }
        if (!ok) res.push_back(id[ve[0]]);
    }
    
    if (res.size() <= 1) cout << -1 << endl;
    else
    {
        cout << res.size() << endl;
        for (auto x : res) cout << x << ' ';
        cout << endl;
    }
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值