C. And Matching
题意:给出一个n和k,要求对由0,1,2,… ,n-1组成的数组,分成n/2对,使每一对两个数的相与的和为k,n为2的次幂,要求给出一种划分方案。
思路:
对于a&b = 0,我们可以定义f(a) = b,至于如何构造,我们发现a=101,b=010,a^b = 111,那么可以由a^(n-1)得到b,因为n是2的次幂,所以n-1就是范围内最长的,
由此我们可以构造出k=0的情况,即0&(n-1),1&(n-2),2&(n-3)…,
交换其中的一些数对,可以得到别的k值,例如对于0<k<n-1的所有情况都可以用k&(n-1),0&(f(k)),其他仍为0,比较特殊的有k=n-1的情况,因为n-1是最大的数了,不能直接&得到,所以可由1+n-2的情况得到,而对于n=4,k=3则无法得到。
#include<bits/stdc++.h>
#define ios ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
typedef long long ll;
typedef unsigned long long ull;
using namespace std;
const int mod=1000000007 , N = 7e4;
const double eps=1e-8;
bool st[N];
int n,k;
int f(int a)
{
return a^(n-1);
}
int main(){
int t;
cin>>t;
while(t--)
{
memset(st,0,sizeof st);
cin>>n>>k;
if(k == 0)
{
for(int i = 0 ; i < n ; i ++ )
if(!st[i])
{
cout<<i<<" "<<f(i)<<'\n';
st[i] = st[f(i)] = 1;
}
}
else if(k == n-1 && n == 4) cout<<"-1\n";
else if(k == n-1 && n != 4)
{
cout<<n-2<<" "<<n-1<<"\n";
cout<<0<<" "<<2<<"\n";
cout<<1<<" "<<n-3<<"\n";
st[0] = st[1] = st[2] = st[n-1] = st[n-2] = st[n-3] = 1;
for(int i = 2 ; i < n ; i ++ )
if(!st[i])
{
cout<<i<<" "<<f(i)<<'\n';
st[i] = st[f(i)] = 1;
}
}
else
{
cout<<k<<" "<<n-1<<"\n";
cout<<0<<" "<<f(k)<<"\n";
st[0] = st[k] = st[n-1] = st[f(k)] = 1;
for(int i = 2 ; i < n ; i ++ )
if(!st[i])
{
cout<<i<<" "<<f(i)<<'\n';
st[i] = st[f(i)] = 1;
}
}
}
return 0;
}