PROBLEM LINK:
Contest Division 1
Contest Division 2
Contest Division 3
Practice
Setter: Daanish Mahajan
Tester: Aryan
Editorialist: Taranpreet Singh
DIFFICULTY
Easy-Medium
PREREQUISITES
Casework and Bitwise operations
PROBLEM
Given integers K and N, find a subset of numbers in the range [1, N] such that the size of the subset is K and the bitwise XOR of the subset is maximum possible.
EXPLANATION
Subtask 1
A Brute force approach would be to try all subsets and considering only subsets of size K, pick the one with maximal XOR. The time complexity of this approach is O(N*2^N), and this shall be sufficient only for the first subtask
Subtask 2
Let us use Dynamic Programming here. Let’s denote state (X, SZ, XOR) as the subset of elements in range [1, X] such that the size of subset is SZ and bitwise XOR of subset elements is XOR. We can make forward transitions from state (X, SZ, XOR) to (X+1, SZ, XOR) if element (X+1) is not included, and to state (X+1, SZ+1, XOR \oplus (X+1)) if element (X+1) is included in subset.
Each state can be represented by a boolean variable, leading to a three-dimensional boolean array depicting whether there exists a subset of first X elements whose size is SZ and whose XOR is XOR.
Additionally, to recover the actual subset, create another three-dimensional boolean array, say P, such that if DP(X, SZ, XOR) is true, then P(X, SZ, XOR) = true reflect that element X is included in the subset which had size SZ and XOR XOR.
This is a well-known technique related to Dynamic Programming, which can be used to recover the actual subset. One example is here.
Code for subtask 2
import java.util.*;
import java.io.*;
class OPTSET{
//SOLUTION BEGIN
void pre() throws Exception{}
void solve(int TC) throws Exception{
int N = ni(), K = ni();
int M = Integer.highestOneBit(N)<<1;
boolean[][][] DP = new boolean[1+N][1+K][M];
boolean[][][] taken = new boolean[1+N][1+K][M];
DP[0][0][0] = true;
for(int i = 0; i< N; i++){
for(int sz = 0; sz <= K; sz++){
for(int xor = 0; xor < M; xor++){
if(!DP[i][sz][xor])continue;
if(!DP[i+1][sz][xor]){
DP[i+1][sz][xor] = true;
taken[i+1][sz][xor] = false;
}
if(sz+1 <= K && !DP[i+1][sz+1][xor^(i+1)]){
DP[i+1][sz+1][xor^(i+1)] = true;
taken[i+1][sz+1][xor^(i+1)] = true;
}
}
}
}
int maxXor = M-1;
while(!DP[N][K][maxXor])maxXor--;
boolean[] inc = new boolean[1+N];
for(int i = N, sz = K, xor = maxXor; i>= 1; i--){
if(taken[i][sz][xor]){
inc[i] = true;
sz--;
xor ^= i;
}
}
for(int i = 1; i<= N; i++)
if(inc[i])
p(i+" ");
pn("");
}
//SOLUTION END
void hold(boolean b)throws Exception{if(!b)throw new Exception("Hold right there, Sparky!");}
static boolean multipleTC = true;
FastReader in;PrintWriter out;
void run() throws Exception{
in = new FastReader();
out = new PrintWriter(System.out);
//Solution Credits: Taranpreet Singh
int T = (multipleTC)?ni():1;
pre();for(int t = 1; t<= T; t++)solve(t);
out.flush();
out.close();
}
public static void main(String[] args) throws Exception{
new OPTSET().run();
}
int bit(long n){return (n==0)?0:(1+bit(n&(n-1)));}
void p(Object o){out.print(o);}
void pn(Object o){out.println(o);}
void pni(Object o){out.println(o);out.flush();}
String n()throws Exception{return in.next();}
String nln()throws Exception{return in.nextLine();}
int ni()throws Exception{return Integer.parseInt(in.next());}
long nl()throws Exception{return Long.parseLong(in.next());}
double nd()throws Exception{return Double.parseDouble(in.next());}
class FastReader{
BufferedReader br;
StringTokenizer st;
public FastReader(){
br = new BufferedReader(new InputStreamReader(System.in));
}
public FastReader(String s) throws Exception{
br = new BufferedReader(new FileReader(s));
}
String next() throws Exception{
while (st == null || !st.hasMoreElements()){
try{
st = new StringTokenizer(br.readLine());
}catch (IOException e){
throw new Exception(e.toString());
}
}
return st.nextToken();
}
String nextLine() throws Exception{
String str = "";
try{
str = br.readLine();
}catch (IOException e){
throw new Exception(e.toString());
}
return str;
}
}
}
Final Subtask
We need to do a lot of casework, trying to find the maximal XOR of the subset.
Let us handle tests with N \leq 7 by subtask 1 solution.
Let’s make cases based on values of K
K = 1
Since we select only 1 element, select N as that leads to maximal XOR
K = 2
We need to select two elements with maximal XOR. Let’s find largest B such that 2^B \leq N. Then 2^{B+1}-1 is the maximal XOR possible from a subset of integers from [1, N]. Let’s pick two integers 2^B and 2^B-1 as their XOR is 2^{B+1}-1
K = N
All elements must be selected.
K = N-1
All but one element must be selected. Let’s compute X = 1 \oplus 2 \oplus \ldots \oplus N. We must exclude element v such that X \oplus v is maximized, which can be easily checked with a single loop.
K = N-2
Now, we need to exclude two elements. Again, let’s include all elements in subset for now and compute X = 1 \oplus 2 \oplus \ldots \oplus N. Now we need to exclude two elements x and y such that X \oplus x \oplus y is maximum possible.
It is easy to prove that maximizing X \oplus x \oplus y is same as minimizing X \oplus (2^{B+1}-1) \oplus x \oplus y. So let’s take X = X \oplus (2^{B+1}-1).
We can see that we need to exclude two elements x and y such that X \oplus x \oplus y is minimum possible, where 1 \leq x, y \leq N and x \neq y
- If X = 0, we cannot make X \oplus x \oplus y = 0 as that requires x = y. So let’s choose x = 2 and y = 3, making X \oplus 2 \oplus 3 = 1
- If X = 2^b for some b, let’s choose x = 2^b+2^c and y = 2^c where c \neq b. Specifically, if b \gt 0, choose c = 0, else choose c = 1. This way, X \oplus x \oplus y = 0
- Otherwise, X has at least two bits set. Let’s choose x = 2^b such that 2^b is the largest power of two less than X, and choose y = X \oplus x. This way, X \oplus x \oplus y = X \oplus x \oplus X \oplus x = 0
All these choices are such that X \oplus x \oplus y becomes minimum possible, as X \oplus x \oplus y is the XOR of remaining two elements XORed with 2^{B+1}-1. So if X \oplus x \oplus y = 0, it implies XOR of remaining elements is 2^{B+1}-1 which is maximum possible.
General case
Now, we have 3 \leq K \leq N-3. We shall do casework just like we did for K = N-2 case.
Let’s include first K elements in subset. Now, we’ll aim to swap some elements from included to not-included and from not-included to included state such that XOR of included elements.
Let’s compute X = 1 \oplus 2 \oplus \ldots \oplus K. Now, this time, our current subset has exactly K elements and has XOR X, so we need to swap some elements from not-included and from include to not-included such that the number of elements remains same, and XOR is maximized.
Let’s try following cases
-
K \lt 2^B-1
We have both 2^B-1 and 2^B not inluded currently, and we see that (2^B-1) \oplus 2^B = 2^{B+1}-1, which is maximum XOR possible. So we’ll add these two elements into subset and remove two elements x and y such that Y = X \oplus x \oplus y becomes minimum possible. Let’s apply similar logic as K = N-2 again- If X = 0, then instead of adding 2^{B-1}-1 and 2^{B-1}, let’s add elements 2^B-2 and 2^B and remove elements 2 and 3 from subset. This way, X \oplus (2^B-2) \oplus 2^B \oplus 2 \oplus 3 = 2^B \oplus (2^B-1) = 2^{B+1}-1
- If X = 2^b for some b, then let’s choose c \neq b.
- If b \gt 0, exclude elements 2^b and 1, and add elements 2^B-2 and 2^B, as X \oplus 2^b \oplus 1 \oplus (2^B-2) \oplus 2^B = 2^{B+1}-1
- If X = 2^0, exclude elements 2 and 3 and add elements 2^B-1 and 2^B, as 1 \oplus 2 \oplus 3 \oplus (2^B-1) \oplus 2^B = 2^{B+1}-1
- Otherwise, X has at least two bits set. Let’s include elements 2^B-1 and 2^B and exclude two elements x = 2^b and y = X \oplus 2^b where 2^b \leq X and b is largest possible.
-
If K = 2^B-1, then simply add element 2^B and remove 2^B-1, making XOR 2^{B+1}-1
-
If K \gt 2^B -1
Now, both 2^B and 2^B-1 are already included. X is the XOR of all elements.- If X \lt 2^B, then we can simply include element K+1 into subset, and remove v = X \oplus (K+1) \oplus (2^{B+1}-1) from subset. We can see that v \lt 2^B, therefore already included in subset.
- Now we have X \geq 2^B. Let’s add two elements x and y into subset such that Y = X \oplus (2^{B+1}-1) \oplus x \oplus y \neq 0. For convenience, include K+1 and one from K+2 and K+3 satisfying above criteria. Additionally, now all elements till 2^B+1 are included in subset. The purpose behind Y \neq 0 is that we now need to exclude two elements w and z from subset such that w \neq z and Y \oplus w \oplus z = 0, which is possible only if Y \gt 0.
- If Y = 2^b for some b, then choose w = 2^b+2^c where c \neq b and z = 2^c. Choose smallest such c.
- Otherwise, Y has atleast 2 bits set. Choose w = 2^b where 2^b \leq Y and b is largest possible, and choose z = Y \oplus w.
If you have managed to follow till here, Congratulations, you have sovled this huge labyrinth of casework. I understand the pain you had to go through to unravel this massive mess.
TIME COMPLEXITY
The time complexity is O(T*log(N) + \sum K)
SOLUTIONS
Setter's Solution
#include<bits/stdc++.h>
# define pb push_back
#define pii pair<int, int>
#define mp make_pair
# define ll long long int
using namespace std;
const int maxt = 10000, maxn = 1e6, maxtn = 4e6, maxk = 1e6, maxtk = 2e6;
const string newln = "\n", space = " ";
bool inc[maxn + 10];
int n, k;
void add(int x){
assert(!inc[x]);
inc[x] = true;
}
void remove(int x){
assert(inc[x]);
inc[x] = false;
}
int hsb(int x){
int ans = -1;
while(x > 0){
x >>= 1; ans++;
}
return ans;
}
int main()
{
int t; int tn = 0, tk = 0;
cin >> t;
while(t--){
cin >> n >> k; tn += n; tk += k;
if(k == 1){
inc[n] = true;
}else{
int b = hsb(n);
if(b <= 2){
int mxr = -1, mid = -1;
for(int i = 1; i < 1 << n; i++){
if(__builtin_popcount(i) != k)continue;
int pxr = 0;
for(int j = 0; j < n; j++){
if((i >> j) & 1)pxr ^= (j + 1);
}
if(pxr > mxr){
mxr = pxr; mid = i;
}
}
for(int j = 0; j < n; j++){
if((mid >> j) & 1)inc[j + 1] = true;
}
}else{
int maxans = (1 << (b + 1)) - 1;
if(n == k){
for(int i = 1; i <= n; i++)inc[i] = true;
}else if(n == k + 1){
int txr = 0;
for(int i = 1; i <= n; i++){
inc[i] = true; txr ^= i;
}
int mxr = -1, skip = -1;
for(int i = 1; i <= n; i++){
if((txr ^ i) > mxr){
mxr = txr ^ i;
skip = i;
}
}
remove(skip);
}else if(n == k + 2){
int txr = maxans;
for(int i = 1; i <= n; i++){
inc[i] = true; txr ^= i;
}
int mb = hsb(txr), first, second;
int sb = __builtin_popcount(txr);
if(sb >= 2){
first = 1 << mb; second = txr ^ first;
}else if(sb == 1){
first = mb == 0 ? 2 : 1; second = (1 << mb) + first;
}else{
first = 2; second = 3;
}
remove(first); remove(second);
txr ^= first ^ second; assert(sb == 0 ? txr == 1 : txr == 0);
}else{
int txr = 0;
for(int i = 1; i <= k; i++){
inc[i] = true; txr ^= i;
}
int sb = __builtin_popcount(txr);
int mb = hsb(txr);
if(k < (1 << b) - 1){
int afirst, asecond, bfirst, bsecond;
if(sb >= 2){
afirst = 1 << b; asecond = afirst - 1;
bfirst = 1 << mb; bsecond = txr ^ bfirst;
}else if(sb == 1){
if(mb == 0){
afirst = 1 << b; asecond = afirst - 1;
bfirst = (1 << mb) + 2; bsecond = 2;
}else{
afirst = 1 << b; asecond = afirst - 2;
bfirst = 1 << mb; bsecond = 1;
}
}else{
afirst = 1 << b; asecond = afirst - 4;
bfirst = 1; bsecond = 2;
}
add(afirst); add(asecond);
remove(bfirst); remove(bsecond);
txr ^= afirst ^ asecond ^ bfirst ^ bsecond; assert(txr == maxans);
}else if(k == (1 << b) - 1){
int first = (1 << b), second = first - 1;
add(first);
remove(second);
txr ^= first ^ second; assert(txr == maxans);
}else{
if(txr & (1 << b)){
int afirst, asecond, bfirst, bsecond;
if((txr ^ (k + 1) ^ (k + 2)) == maxans){
afirst = k + 1; asecond = k + 3;
}else{
afirst = k + 1; asecond = k + 2;
}
txr ^= afirst ^ asecond;
assert(txr != maxans);
txr ^= maxans;
int mb = hsb(txr);
if(__builtin_popcount(txr) >= 2){
bfirst = 1 << mb; bsecond = bfirst ^ txr;
}else{
bfirst = mb == 0 ? 2 : 1; bsecond = (1 << mb) + bfirst;
}
add(afirst); add(asecond);
remove(bfirst); remove(bsecond);
txr ^= bfirst ^ bsecond; assert(txr == 0);
}else{
int first = k + 1, second = txr ^ first ^ maxans;
add(first);
remove(second);
}
}
}
}
}
int ck = 0, txr = 0;
for(int i = 1; i <= n; i++){
if(inc[i]){
txr ^= i;
cout << i << (ck == k - 1 ? newln : space);
inc[i] = false; ck++;
}
}
assert(ck == k);
}
assert(tn <= maxtn); assert(tk <= maxtk);
}
Tester's Solution
/* in the name of Anton */
/*
Compete against Yourself.
Author - Aryan (@aryanc403)
Atcoder library - https://atcoder.github.io/ac-library/production/document_en/
*/
#ifdef ARYANC403
#include <header.h>
#else
#pragma GCC optimize ("Ofast")
#pragma GCC target ("sse,sse2,sse3,ssse3,sse4,popcnt,abm,mmx,avx")
//#pragma GCC optimize ("-ffloat-store")
#include<bits/stdc++.h>
#define dbg(args...) 42;
#endif
using namespace std;
#define fo(i,n) for(i=0;i<(n);++i)
#define repA(i,j,n) for(i=(j);i<=(n);++i)
#define repD(i,j,n) for(i=(j);i>=(n);--i)
#define all(x) begin(x), end(x)
#define sz(x) ((lli)(x).size())
#define pb push_back
#define mp make_pair
#define X first
#define Y second
#define endl "\n"
typedef long long int lli;
typedef long double mytype;
typedef pair<lli,lli> ii;
typedef vector<ii> vii;
typedef vector<lli> vi;
const auto start_time = std::chrono::high_resolution_clock::now();
void aryanc403()
{
#ifdef ARYANC403
auto end_time = std::chrono::high_resolution_clock::now();
std::chrono::duration<double> diff = end_time-start_time;
cerr<<"Time Taken : "<<diff.count()<<"\n";
#endif
}
long long readInt(long long l, long long r, char endd) {
long long x=0;
int cnt=0;
int fi=-1;
bool is_neg=false;
while(true) {
char g=getchar();
if(g=='-') {
assert(fi==-1);
is_neg=true;
continue;
}
if('0'<=g&&g<='9') {
x*=10;
x+=g-'0';
if(cnt==0) {
fi=g-'0';
}
cnt++;
assert(fi!=0 || cnt==1);
assert(fi!=0 || is_neg==false);
assert(!(cnt>19 || ( cnt==19 && fi>1) ));
} else if(g==endd) {
if(is_neg) {
x=-x;
}
assert(l<=x&&x<=r);
return x;
} else {
assert(false);
}
}
}
string readString(int l, int r, char endd) {
string ret="";
int cnt=0;
while(true) {
char g=getchar();
assert(g!=-1);
if(g==endd) {
break;
}
cnt++;
ret+=g;
}
assert(l<=cnt&&cnt<=r);
return ret;
}
long long readIntSp(long long l, long long r) {
return readInt(l,r,' ');
}
long long readIntLn(long long l, long long r) {
return readInt(l,r,'\n');
}
string readStringLn(int l, int r) {
return readString(l,r,'\n');
}
string readStringSp(int l, int r) {
return readString(l,r,' ');
}
void readEOF(){
assert(getchar()==EOF);
}
vi readVectorInt(int n,lli l,lli r){
vi a(n);
for(int i=0;i<n-1;++i)
a[i]=readIntSp(l,r);
a[n-1]=readIntLn(l,r);
return a;
}
const lli INF = 0xFFFFFFFFFFFFFFFL;
lli seed;
mt19937 rng(seed=chrono::steady_clock::now().time_since_epoch().count());
inline lli rnd(lli l=0,lli r=INF)
{return uniform_int_distribution<lli>(l,r)(rng);}
class CMP
{public:
bool operator()(ii a , ii b) //For min priority_queue .
{ return ! ( a.X < b.X || ( a.X==b.X && a.Y <= b.Y )); }};
void add( map<lli,lli> &m, lli x,lli cnt=1)
{
auto jt=m.find(x);
if(jt==m.end()) m.insert({x,cnt});
else jt->Y+=cnt;
}
void del( map<lli,lli> &m, lli x,lli cnt=1)
{
auto jt=m.find(x);
if(jt->Y<=cnt) m.erase(jt);
else jt->Y-=cnt;
}
bool cmp(const ii &a,const ii &b)
{
return a.X<b.X||(a.X==b.X&&a.Y<b.Y);
}
#define bcnt(x) (__builtin_popcountll(x))
const lli mod = 1000000007L;
// const lli maxN = 1000000007L;
lli getMsb(lli n){
const lli logN=30;
for(lli i=logN;i>=0;i--){
if(n&(1LL<<i))
return i;
}
dbg(n);
assert(false);
}
void bruteforce(lli n,lli k){
lli mx=-1,ans=0;
for(lli msk=0;msk<(1LL<<n);++msk){
if(bcnt(msk)!=k)
continue;
lli cur=0;
for(lli j=0;j<n;++j){
if(msk&(1LL<<j))
cur^=j+1;
}
if(cur>mx){
mx=cur;
ans=msk;
}
}
for(lli j=0;j<n;++j){
if(ans&(1LL<<j))
cout<<j+1<<" ";
}
cout<<endl;
}
void solve(lli n,lli k){
if(n<8){
bruteforce(n,k);
return;
}
dbg(n,k);
const lli msb=getMsb(n);
const lli mxAns=(2LL<<msb)-1;
vi vis(n+1);
bool fl=true;
if(k==1){
vis[n]=1;
fl=false;
}
else if(k==n){
fl=false;
vis=vi(n+1,1);
} else if(k==n-1){
fl=false;
lli cnt=0;
for(lli i=1;i<=n;++i)
cnt^=i;
lli rmv=1;
for(lli i=1;i<=n;++i){
if((cnt^i)>(cnt^rmv))
rmv=i;
}
vis=vi(n+1,1);
vis[rmv]=0;
} else if(k==n-2){
lli cnt=0;
for(lli i=1;i<=n;++i)
cnt^=i;
cnt^=mxAns;
vis=vi(n+1,1);
const lli bitc=__builtin_popcountll(cnt);
if(bitc>=2)
{
const lli f=getMsb(cnt);
vis[1LL<<f]=vis[cnt^(1LL<<f)]=0;
}
else if(bitc==1)
{
const lli f=getMsb(cnt);
const lli b=(f?0:1);
vis[1LL<<b]=vis[cnt^(1LL<<b)]=0;
}
else
{
vis[1LL<<msb]=vis[(1LL<<msb)+1]=0;
fl=false;
}
} else {
lli cnt=0;
for(lli i=1;i<=k;++i){
cnt^=i;
vis[i]=1;
}
if(k<(1LL<<msb)-1){
const lli bitc = bcnt(cnt);
if(bitc>=2){
vis[1LL<<msb]=vis[(1LL<<msb)-1]=1;
cnt^=(1LL<<msb)^((1LL<<msb)-1)^mxAns;
const lli f=getMsb(cnt);
vis[1LL<<f]=vis[cnt^(1LL<<f)]=0;
}
else if(bitc==1) {
const lli f=getMsb(cnt);
if(f){
vis[(1LL<<msb)]=vis[(1LL<<msb)-2]=1;
vis[cnt]=vis[1]=0;
} else {
vis[(1LL<<msb)]=vis[(1LL<<msb)-1]=1;
vis[cnt^2]=vis[2]=0;
}
} else {
vis[(1LL<<msb)]=vis[(1LL<<msb)-4]=1;
vis[1]=vis[2]=0;
}
} else if(k==(1LL<<msb)-1){
vis[1LL<<msb]=1;
vis[(1LL<<msb)-1]=0;
} else {
if((cnt&(1LL<<msb))==0){
vis[k+1]=1;
cnt^=k+1;
vis[cnt^mxAns]=0;
} else {
cnt^=k+1;
vis[k+1]=1;
if((cnt^(k+2))==mxAns){
cnt^=k+3;
vis[k+3]=1;
} else{
cnt^=k+2;
vis[k+2]=1;
}
cnt^=mxAns;
const lli bitc=bcnt(cnt);
if(bitc>=2){
const lli f=getMsb(cnt);
vis[1LL<<f]=vis[cnt^(1LL<<f)]=0;
} else {
const lli f=getMsb(cnt);
const lli b=(f?0:1);
vis[1LL<<b]=vis[cnt^(1LL<<b)]=0;
}
}
}
}
lli ans=0,val=0;
for(lli i=1;i<=n;++i){
if(vis[i])
{
cout<<i<<" ";
ans^=i;
val++;
}
}
// cout<<ans;
dbg(vis);
assert(val==k);
if(fl){
dbg(n,k,ans);
assert(ans==(2LL<<msb)-1);
}
cout<<endl;
}
int main(void) {
ios_base::sync_with_stdio(false);cin.tie(NULL);
// freopen("txt.in", "r", stdin);
// freopen("txt.out", "w", stdout);
// cout<<std::fixed<<std::setprecision(35);
lli T=readIntLn(1,1e4);
lli sumn=0,sumk=0;
while(T--)
{
const lli n=readIntSp(1,1e6);
const lli k=readIntLn(1,n);
sumn+=n;
sumk+=k;
assert(sumn<=4e6);
assert(sumk<=2e6);
solve(n,k);
} aryanc403();
readEOF();
return 0;
}
Editorialist's Solution
import java.util.*;
import java.io.*;
class OPTSET{
//SOLUTION BEGIN
void pre() throws Exception{}
void solve(int TC) throws Exception{
int N = ni(), K = ni();
int maxAns = (Integer.highestOneBit(N)<<1)-1;
//M-1 is the maximum XOR possible
boolean[] inc = new boolean[1+N];
if(N <= 7){
int best = brute(N, K);
for(int i = 0; i< N; i++)if(((best>>i)&1) == 1)inc[i+1] = true;
}else if(K == 1){
inc[N] = true;
}else if(K == 2){
int B = Integer.highestOneBit(N);
//V^(V-1) = M-1 holds
inc[B-1] = inc[B] = true;
}else if(K == N){
for(int i = 1; i<= N; i++)inc[i] = true;
}else if(K+1 == N){
//Try excluding each element one by one, and pick the choice leading to maximal XOR
int X = 0;
for(int i = 1; i<= N; i++)X ^= i;
int exc = 0, xor = -1;
for(int i = 1; i<= N; i++)if((X^i) > xor){
exc = i;
xor = X^i;
}
//exc is the element excluded
for(int i = 1; i<= N; i++)if(i != exc)inc[i] = true;
}else if(K+2 == N){
int XOR = 0;
for(int i = 1; i<= N; i++){
inc[i] = true;
XOR ^= i;
}
XOR ^= maxAns;
//Now we want to flip 2 positions x and y such that x^y = XOR
//Deleting two elements x and y such that x^y = XOR
if(bitCount(XOR) >= 2){
int x = Integer.highestOneBit(XOR), y = XOR^x;
inc[x] = inc[y] = false;
}else if(bitCount(XOR) == 1){
if(XOR == 1){
int x = 2, y = 3;
inc[x] = inc[y] = false;
}else{
int x = XOR^1, y = 1;
inc[x] = inc[y] = false;
}
}else{
//We cannot achieve maxAns, so we achieve maxAns-1 by removing x and y such that x^y = 1
int x = Integer.highestOneBit(N), y = x+1;
inc[x] = inc[y] = false;
}
}else{
//3 <= K <= N-3
int XOR = 0;
for(int i = 1; i<= K; i++){
inc[i] = true;
XOR ^= i;
}
int B = Integer.highestOneBit(N);
if(K < B-1){
int btc = bitCount(XOR);
if(btc >= 2){
inc[B-1] = inc[B] = true;
XOR ^= (B-1)^B^maxAns;
int x = Integer.highestOneBit(XOR), y = XOR^x;
inc[x] = inc[y] = false;
}else if(btc == 1){
if(XOR == 1){
inc[B-1] = inc[B] = true;
inc[2] = inc[3] = false;
}else{
inc[B-2] = inc[B] = true;
inc[XOR] = inc[1] = false;
}
}else{
inc[B] = inc[B-2] = true;
inc[2] = inc[3] = false;
}
}else if(K == B-1){
inc[B] = true;
inc[B-1] = false;
}else{
if((XOR & B) == 0){
inc[K+1] = true;
XOR ^= K+1;
inc[XOR^maxAns] = false;//XOR^maxAns shall have highest bit off, hence included in subset
}else{
if((XOR^(K+1)^(K+2)) == maxAns){
inc[K+1] = inc[K+3] = true;
XOR ^= (K+1)^(K+3);
}else{
inc[K+1] = inc[K+2] = true;
XOR ^= (K+1)^(K+2);
}
XOR ^= maxAns;
if(bitCount(XOR) >= 2){
int x = Integer.highestOneBit(XOR), y = XOR^x;
inc[x] = inc[y] = false;
}else{
if(XOR == 1){
inc[2] = inc[3] = false;
}else{
inc[XOR+1] = inc[1] = false;
}
}
}
}
}
for(int i = 1; i<= N; i++)
if(inc[i])
p(i+" ");
pn("");
}
int bitCount(int x){
return x == 0?0:(1+bitCount(x&(x-1)));
}
int brute(int N, int K){
int best = 0, maxXor = -1;
for(int mask = 1; mask < 1<<N; mask++){
if(bitCount(mask) != K)continue;
int XOR = 0;
for(int i = 0; i< N; i++)if(((mask>>i)&1)==1)XOR ^= (1+i);
if(XOR > maxXor){
maxXor = XOR;
best = mask;
}
}
return best;
}
void dbg(Object... o){System.err.println(Arrays.deepToString(o));}
//SOLUTION END
void hold(boolean b)throws Exception{if(!b)throw new Exception("Hold right there, Sparky!");}
static boolean multipleTC = true;
FastReader in;PrintWriter out;
void run() throws Exception{
in = new FastReader();
out = new PrintWriter(System.out);
//Solution Credits: Taranpreet Singh
int T = (multipleTC)?ni():1;
pre();for(int t = 1; t<= T; t++)solve(t);
out.flush();
out.close();
}
public static void main(String[] args) throws Exception{
new OPTSET().run();
}
int bit(long n){return (n==0)?0:(1+bit(n&(n-1)));}
void p(Object o){out.print(o);}
void pn(Object o){out.println(o);}
void pni(Object o){out.println(o);out.flush();}
String n()throws Exception{return in.next();}
String nln()throws Exception{return in.nextLine();}
int ni()throws Exception{return Integer.parseInt(in.next());}
long nl()throws Exception{return Long.parseLong(in.next());}
double nd()throws Exception{return Double.parseDouble(in.next());}
class FastReader{
BufferedReader br;
StringTokenizer st;
public FastReader(){
br = new BufferedReader(new InputStreamReader(System.in));
}
public FastReader(String s) throws Exception{
br = new BufferedReader(new FileReader(s));
}
String next() throws Exception{
while (st == null || !st.hasMoreElements()){
try{
st = new StringTokenizer(br.readLine());
}catch (IOException e){
throw new Exception(e.toString());
}
}
return st.nextToken();
}
String nextLine() throws Exception{
String str = "";
try{
str = br.readLine();
}catch (IOException e){
throw new Exception(e.toString());
}
return str;
}
}
}
Feel free to share your approach. Suggestions are welcomed as always.