提答题。(其实也可以是传统题)
在([1,n])的整数中选出一个集合,要求两两异或不同。让这个集合尽量大。
(n< 2^{24})
答案阈值大概在(2^k)级别,其中(2^{2k}=O(n))。
做法:定义一个多项式的域,多项式系数模(2),模某个(k)次不可约多项式意义下。对于(iin [1,2^k))((i)为一个多项式,用二进制表示),把二元组((i^3,i))作为答案(即将两个二进制数拼接在一起)。此时答案为(2^k-1),补一个(2^{2k})(二进制数)就有(2^k)了。
注意可能要进行一些微调。
(下面不区分加法和异或,并且加法和减法等价)
证明:考虑在这个意义下,如果存在((a^3,a)+(b^3,b)=(c^3,c)+(d^3,d)),即(a^3+b^3=c^3+d^3,a+b=c+d),则:
[a^2+ab+b^2=c^2+cd+d^2\
ab=cd\
在方程x^2-(a+b)x+ab=0中,{a,b}和{c,d}都是解。\
herefore {a,b}={c,d}
]
所以如果(a,b,c,d),则不可能冲突。
另外找(k)次不可约多项式可以直接类似于素数筛法搞。
using namespace std;
#include <bits/stdc++.h>
int n,k;
const int tab[13]={1,2,7,11,19,37,67,131,283,515,1033,2053,4105};
int mul(int a,int b){
int c=0;
for (int i=0;i<=k;++i)
if (a>>i&1)
c^=b<<i;
return c;
}
int lg(int a){
int s=0;
for (;a;a>>=1)
s++;
return s-1;
}
int di(int c,int a){
int _c=c,b=0,w=lg(a);
for (int i=k+k-1;i>=w;--i)
if (c>>i&1){
b^=1<<i-w;
c^=a<<i-w;
}
// if ((mul(a,b)^c)!=_c)
// printf("fuck
");
return b;
}
int mod(int a,int p){
return a^mul(di(a,p),p);
}
int ans[1<<25|5];
int bz[1<<25|5];
int main(int argc,char *argv[]){
freopen(argv[1],"r",stdin);
freopen(argv[2],"w",stdout);
scanf("%d",&n);
for (k=0;1<<k*2<=n;++k);//此处需要微调
int p=tab[k];
for (int i=1;i<1<<k;++i){
int x=i,y=mod(mul(mod(mul(i,i),p),i),p);
ans[i]=x<<k|y;
// ans[i]=y<<k|x;
}
ans[0]=1<<k*2;
for (int i=0;i<1<<k;++i)
for (int j=0;j<i;++j)
if (bz[ans[i]^ans[j]]){
printf("-1
");
return 0;
}
else
bz[ans[i]^ans[j]]=1;
int cnt=0;
for (int i=0;i<1<<k;++i)
if (ans[i]<=n)
cnt++;
printf("%d
",cnt);
for (int i=0;i<1<<k;++i)
if (ans[i]<=n)
printf("%d
",ans[i]);
return 0;
}