题目链接:
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; }