Problem - D - Codeforces
给出两个整数nn和xx,构造一个满足以下条件的数组:
对于数组中的任何元素aiai,1≤ai<2n1≤ai<2n;
没有非空的子段,其位数XOR值等于00或xx、
它的长度ll应该是最大的。
一个序列bb是一个序列aa的子段,如果bb可以通过从aa中删除几个(可能是零或全部)元素开始和几个(可能是零或全部)元素结束得到。
输入
唯一一行包含两个整数nn和xx(1≤n≤181≤n≤18,1≤x<2181≤x<218)。
输出
第一行应该包含数组ll的长度。
如果ll是正数,第二行应包含ll个空间分隔的整数a1a1,a2a2,......,alal(1≤ai<2n1≤ai<2n)--数组aa的元素。
如果有多个解决方案,打印其中任何一个。
例子
输入
拷贝
3 5
输出
复制
3
6 1 3
输入
复制
2 4
输出
复制
3
1 3 1
输入
复制
1 1
输出
拷贝
0
注意
在第一个例子中,子段的位数XOR是{6,7,4,1,2,3}{6,7,4,1,2,3}。
题解:
1.任何子段异或和不为0
2.任何子段异或和不为x
我们可以从小到大枚举i,看i^x是否出现过,出现过则跳过,否则记录下来,
f[0] = 1,因为数组中不能出现x,f[i] = 1
这样的用处是,使得我们记录数组中任意两个数得异或和,不会为x
但是依旧好像没什么用
但是其实我们直接输出,a[i]^a[i-1]就是答案
为啥?
打个比方,数组中存的是,1,2,3,4,5
输出是
1^0
2^1
3^2
4^3
5^4
这样就能比较明显得看出来,任意子段得异或和,答案都相当于,我们记录数组中的两个数得异或和,而我们保证了记录数组中任意两个数得异或和,不会为x,所以成立
#include <cstdio>
#include <cstring>
#include <algorithm>
#include<iostream>
#include<vector>
#include<set>
#include<map>
#include<cmath>
#include<queue>
using namespace std;
typedef long long ll;
typedef pair<int,int> PII;
//#define int long long
int a[1000050];
void solve()
{
int n,x;
cin >> n >> x;
map<int,int> f;
f[0] = 1;
int cnt = 0;
for(int i = 1;i < 1 << n;i++)
{
if(f[i^x])
continue;
a[++cnt] = i;
f[i] = 1;
}
cout << cnt <<"\n";
for(int i = 1;i <= cnt;i++)
{
cout << (a[i] ^ a[i - 1]) <<" ";
}
}
//111
//110
//100
//011
signed main()
{
// ios::sync_with_stdio(0);
// cin.tie(0);cout.tie(0);
int t = 1;
// cin >> t;
while(t--)
{
solve();
}
}