题目链接:
http://codeforces.com/contest/1174/problem/D
题意:
构造一个序列,满足以下条件
- 他的所有子段的异或值不等于$x$
- $1 \le a_i<2^n$
输出一个最长的这样的序列
数据范围:
$1 \le n \le 18$
$1 \le x<2^{18}$
分析:
比赛的时候搞混$subsegment$和$subsequence$,前者为子段一定要连续,后者为子序列可以不连续
赛后看的官方题解
假设构造的序列为$a_i$,它的前缀异或和为$b_i$
即:$b_i=a_1\bigoplus a_2 \bigoplus a_3\bigoplus a_4.....\bigoplus a_i$
$b_i$必须满足以下条件
- 没有重复的元素即$b_i\neq b_j$
- 没有一对元素的异或值为$x$
- 里面没有$x$
关于第二条,我们可以知道,如果$g$加入在$b$数组中,那么$g\bigoplus x$不在$b$数组中,所以这两个数选其中之一就行
得到b数组之后$a_i=b_i \oplus b_{i-1}$
ac代码:
#include<bits/stdc++.h>
#define ll long long
#define pa pair<int,int>
using namespace std;
const int maxn=1e5+10;
const int maxm=1e6+10;
const ll mod=998244353;
int ans[maxn];
inline ll cal(int st,int len)
{
return (ll)len*(2*st+len-1)/2;
}
int main()
{
int n,k;
while(scanf("%d %d",&n,&k)==2)
{
if(cal(1,k)>n)
{
printf("NO\n");
continue;
}
if(n==4&&k==2)
{
printf("NO\n");
continue;
}
else if(n==8&&k==3)
{
printf("NO\n");
continue;
}
int st=1,en=n;
while(st!=en)
{
int md=(st+en)/2;
if(cal(md+1,k)<=n)st=md+1;
else en=md;
}
for(int i=1;i<=k;i++)
ans[i]=st+i-1;
int now=n-cal(st,k),inde=k;
while(now)
{
if(ans[inde]+1<=2*ans[inde-1])ans[inde]++,inde--,now--;
else inde=k;
}
printf("YES\n");
for(int i=1;i<=k;i++)
{
printf("%d",ans[i]);
if(i==k)printf("\n");
else printf(" ");
}
}
return 0;
}