题目描述
大意
给你一个含n 个(n总是2的幂)元素的数组,其中包含所有整数0,1,2,… ,n-1。找到 n/2对元素满足:
集合中的每个元素正好是一对。
它的元素的按位 AND 对的所有对的和必须完全等于 k。
分析
为了方便找到规律,下面将以n=8
为例,下图给出了各个元素及其二进制表达
-
当 k<n-1 时
- 通过图中所示我们不难发现
u
位置上的数与n-1-u
位置上的数相与为零,最初先以这样的形式配对(即对称位置为一对)。 - 而0与任何数相与为0,任何数相与
n-1
为它本身 - 则要想满足相与和为
k
,只需要将k
与1配对,k'
(k之前做配对的数)与0配对即可 - 交换改变配对的位置,其余不变
- 通过图中所示我们不难发现
-
当 k=n-1时
- 上述点换的方法不在适用,因为特殊数
n-1
不可重复使用 - 循着出发点为尽量用较少的对得到相应和,可以先将
n-1
与n-2
相与得到n-2
的值 - 所需要在加上的1可以通过1与
n-3
相与 - 此时为保证其它对相与为零,还需要将0与2配对
- 在对称配对的基础上,交换改变配对的位置,其余不变
- 上述点换的方法不在适用,因为特殊数
-
注意:
n=4 k=n-1
时使找不到方案的。因n-1
值为1.重复使用
code
#include<bits/stdc++.h>
using namespace std;
int n, m, k, t;
const int N = 1e5 + 10;
void solve()
{
int a[N] = {0}, b[N] = {0};
cin >> n >> k;
for(int i = 0; i < n/2; i ++)
{
a[i] = i;
b[i] = n - 1 - i;
}
if(k == n - 1 && n == 4)
{
puts("-1");
return;
}
if(k >= 0 && k < n / 2)
{
a[0] = k;
a[k] = 0;
}
else if(k >= n / 2 && k < n - 1)
{
b[n - 1 - k] = 0;
a[0] = k;
}
else
{
a[0] = 0, b[0] = 2;
a[1] = 1, b[1] = n - 3;
a[2] = n - 1, b[2] = n - 2;
}
for(int i = 0; i < n / 2; i ++)
cout << a[i] << " " << b[i] << "\n";
}
int main()
{
cin >> t;
while(t --)
{
solve();
}
return 0;
}