CF1787E The Harmonization of XOR 题解
我甚至都忘记什么时候写的这玩意了。
由于异或满足交换律和结合律,所以首先需要保证 \(1\) 到 \(n\) 所有数字异或和等于 \(k\) 组的异或和。
其次我们考虑到 \(x \oplus x \oplus x=x\),也就是说 \(3\) 组可以合并成 \(1\) 组,所以我们只需要最大化能够分的组数。
考虑最大化组数的一个方法:
- 如果 \(x\) 存在,单独分组
- 其余两两一组
- 剩下的在一组
证明:设 \(B\) 为 \(x\) 的最高位,即 \(x\) 的第 \(B\) 位为 \(1\)(类似 popcount)
设 \(M\) 是从 \(1\) 到 \(n\) 的数字,并且使得第 \(B\) 位为 \(1\) 的数量,显然答案小于等于 \(M\),因为在每个组中,必须至少有一个数字表示第 \(B\) 位为 \(1\)。
这 \(M\) 个数字异或 \(x\) 之后肯定更小,所以一定存在 \(M\) 组。
时间复杂度 \(O(n)\)。
int n,k,x,p[maxn],vis[maxn];
int getsum(int x){ int i,s=0; for(i=1;i<=x;i++) s^=i; return s; }
struct JTZ{ int x,y; }a[maxn]; int cnt,now;
void work(){
n=read(); k=read(); x=read(); int i; if((k&1)?getsum(n)!=x:getsum(n)){ puts("NO"); return; }
cnt=now=0; for(i=1;i<=n;i++) p[i]=vis[i]=0;
for(i=1;i<=n;i++){
if(i==x) a[++cnt]=(JTZ){i,0},p[i]=1;
if((i^x)<=n&&!p[i]&&!p[i^x]) p[i]=1,p[i^x]=1,a[++cnt]=(JTZ){i,i^x};
} if(cnt<k){ puts("NO"); return; } puts("YES");
for(i=1;i<k;i++){
if(a[i].y) pc('2'),pc(' '),print(a[i].x),pc(' '),print(a[i].y),pc('\n'),now+=2;
else pc('1'),pc(' '),print(a[i].x),pc('\n'),now++;
vis[a[i].x]=vis[a[i].y]=1;
} print(n-now),pc(' ');
for(i=1;i<=n;i++) if(!vis[i]) print(i),pc(' ');
pc('\n'); return;
}