专栏文章

题解:P11192 [COTS 2021] 菜 Jelo

P11192题解参与者 2已保存评论 1

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
1 条
当前快照
1 份
快照标识符
@miqu5gxb
此快照首次捕获于
2025/12/04 10:47
3 个月前
此快照最后确认于
2025/12/04 10:47
3 个月前
查看原文

题意

构造一个大小为 2N22^{\frac N 2}{0,1,,2N1}\{0,1,\cdots,2^N-1\} 的子集,满足子集中元素两两异或和均不同。

思路

n=N2n=\dfrac N 2。注意区分大小写。
把一个数拆成前半段和后半段,长度均为 nn。由于要构造的集合大小是 2n2^n,我们猜测前半段任意填,后半段是关于前半段的函数。设前半段为 x[0,2n)x\in[0,2^n),后半段为 f(x)[0,2n)f(x)\in[0,2^n)
既然已经是异或了,我们再用普通的加法乘法肯定不方便。模仿这道题,我们构造有限域 F2n\mathbb F_{2^n},下面的所有加法和乘法未经说明都是这个有限域里的。
假设存在两对(无序对)元素 {(a,f(a)),(b,f(b))},{(c,f(c)),(d,f(d))}\{(a,f(a)),(b,f(b))\},\{(c,f(c)),(d,f(d))\},满足它们异或和相同。由于我们是拼起来的,前后对于异或独立,所以有方程组 a+b=c+d,f(a)+f(b)=f(c)+f(d)a+b=c+d,f(a)+f(b)=f(c)+f(d)
我们对 ff 的构造要满足这个方程有且仅有两个解,即说明 {a,b}={c,d}\{a,b\}=\{c,d\}
只有两个解那就是二次方程喽。那我们直接让 ff 变成二次函数,比如 f(x)=x2f(x)=x^2
带回上面的方程,我们有 a+b=c+d,a2+b2=c2+d2a+b=c+d,a^2+b^2=c^2+d^2
把第一个式子平方减去第二个式子,得到 ab=cdab=cd
和相等,积也相等。这是什么🤔?韦达定理呀。我们有 {a,b},{c,d}\{a,b\},\{c,d\} 都是方程 x2(a+b)x+ab=0x^2-(a+b)x+ab=0 的一组解,即 {a,b}={c,d}\{a,b\}=\{c,d\}
我们只需要求出 2n2^n 阶的有限域就可以了。
你高高兴兴写了代码,跑出来一看,n=4n=4 都过不去。
为什么?
在实数域下,平方是不存在逆的。在有限域下用平方是很危险的。
如何解决呢?我们又不想放弃韦达定理。
是不是改成三次方就可以了?
此时 a+b=c+d,a3+b3=c3+d3a+b=c+d,a^3+b^3=c^3+d^3,一式立方减二式,得到 ab(a+b)=cd(c+d)ab(a+b)=cd(c+d),即 ab=cdab=cd。也是可以用韦达定理的。
于是就解决了。

代码

CPP
#include<bits/stdc++.h>
#define F(i,a,b) for(int i(a),i##i##end(b);i<=i##i##end;++i)
#define R(i,a,b) for(int i(a),i##i##end(b);i>=i##i##end;--i) 
#define ll long long
using namespace std;
int m,p;
inline ll qpow(ll base,int expo){
	ll res(1);
	while(expo){
		(expo&1)&&(res=res&base);
		base=base&base,expo>>=1;
	}
	return res;
}
bool type;
struct poly{
	int num[100]={};
	int len=0;
	inline void init(){
		while(!num[len]&&len>0) --len;
		return;
	}
	inline void turn(int t){
		while(t) num[len++]=t&1,t>>=1;
		init();
		return;
	}
	inline poly operator+(const poly&a)const{
		poly res;
		res.len=max(a.len,len);
		F(i,0,res.len) res.num[i]=num[i]^a.num[i];
		res.init();
		return res;
	}
	inline poly operator+(const int a)const{
		poly res=*this;
		int&qwq(res.num[0]);
		qwq^=a;
		return res;
	}
	inline poly operator-(const poly&a)const{
		return a+*this;
	}
	inline poly operator-(const int a)const{
		return *this+a;
	}
	inline poly operator*(const poly&a)const{
		poly x;
		F(i,0,len) F(j,0,a.len){
			int&qwq(x.num[i+j]);
			qwq^=(a.num[j]&num[i]);
		}
		x.len=len+a.len;
		x.init();
		return x;
	}
	inline poly operator*(const int a)const{
		poly res=*this;
		F(i,0,len){
			int&qwq(res.num[i]);
			qwq=a&qwq;
		}
		return res;
	}
	inline bool operator<=(const poly&a)const{
		if(type) return len<=a.len;
		if(len!=a.len) return len<=a.len;
		R(i,len,0) if(num[i]!=a.num[i]) return num[i]<=a.num[i];
		return 1;
	}
	inline poly operator<<(const int a)const{
		poly res;
		res.len=a+len;
		F(i,0,len) res.num[a+i]=num[i];
		return res;
	}
	inline poly operator%(const poly&a)const{
		poly t=*this;
		while(a<=t){
			poly tmp=a*t.num[t.len];
			t=t-(tmp<<(t.len-a.len));
		}
		t.init();
		return t;
	}
	inline bool check()const{
		poly x=*this,y;
		F(i,2,(1<<m)-1){
			poly t;
			t.turn(i);
			y=x%t;
			if(y.len==0&&y.num[0]==0) return 0;
		}
		return 1;
	}
	inline void output(){
		F(i,0,m) cout<<num[i]<<" ";
		cout<<"\n";
		return;
	}
	inline int decode(){
		int res(0);
		R(i,len,0) res=(res<<1)|num[i];
		return res;
	}
}mod;
inline void findmod(){
	R(i,(1<<m)-1,1){
		poly a;
		a.turn(i);
		a.num[m]=1;
		a.len=m;
		if(a.check()){
			mod=a;
			return;
		}
	}
}
int main(){
	ios::sync_with_stdio(0);
	cin.tie(0),cout.tie(0); 
	cin>>m;
	m/=2;
	findmod();
	type=1;
	cout<<(1<<m)<<"\n";
	F(i,0,(1<<m)-1){
		int qwq=i<<m;
		poly qaq;
		qaq.turn(i);
		qwq|=(qaq*qaq*qaq%mod).decode();
		cout<<qwq<<" ";
	}
	return 0;
}

评论

1 条评论,欢迎与作者交流。

正在加载评论...