猜猜这篇过多久才会被码农教程爬qwq。
好高妙啊。
考虑按位考虑。定义 \(f(x , d)\) , 表示所有与 \(x\) 最多只有前 \(d\) 位不同的所有 \(a_i\) 异或 \(x\) 的最小差。
考虑 \(d\) 增加 1 , 那么会多上一些 \(d + 1\) 位与 \(x\) 不同的数。
三种情况,答案在原集合,新集合,各占一个。
原集合容易处理,新集合就是 \(f(y , d) + 2^d\) ,其中 \(y\) 是只有 \(d + 1\) 位与 \(x\) 不同的数。
各占一个的情况,注意到新集合的数异或 \(x\) 的结果一定大于原集合的结果。因此维护 \(mxv(x , d)\) / \(miv(x , d)\) 表示所有与 \(x\) 只有前 \(d\) 位不同的所有 \(a_i\) 异或的最大/小值。
那么各占一个的贡献就是 \(miv(y , d) + 2^d - mxv(x , d)\)。
同时这两个新的东西会相当好维护,令 \(d\) 增加 1 ,讨论一下就好了。
#include <map>
#include <set>
#include <queue>
#include <cmath>
#include <bitset>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define pii pair <int , int>
#define pll pair <LL , LL>
#define mp make_pair
#define fs first
#define sc second
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
//const int Mxdt=100000;
//static char buf[Mxdt],*p1=buf,*p2=buf;
//#define getchar() p1==p2&&(p2=(p1=buf)+fread(buf,1,Mxdt,stdin),p1==p2)?EOF:*p1++;
template <typename T>
void read(T &x) {
T f=1;x=0;char s=getchar();
while(s<'0'||s>'9') {if(s=='-') f=-1;s=getchar();}
while(s>='0'&&s<='9') {x=(x<<3)+(x<<1)+(s-'0');s=getchar();}
x *= f;
}
template <typename T>
void write(T x , char s='\n') {
if(!x) {putchar('0');putchar(s);return;}
if(x<0) {putchar('-');x=-x;}
T tmp[25]={},t=0;
while(x) tmp[t++]=x%10,x/=10;
while(t-->0) putchar(tmp[t]+'0');
putchar(s);
}
int n , k , a[(1 << 20) + 5] , vis[(1 << 20) + 5];
int mav[(1 << 20) + 5][21] , miv[(1 << 20) + 5][21];
int f[(1 << 20) + 5][21] , ans[(1 << 20) + 5];
int main() {
read(n),read(k);
for (int i = 1; i <= n; ++i) read(a[i]) , vis[a[i]] = 1;
for (int s = 0; s < (1 << k); ++s) {
mav[s][0] = -1e9;miv[s][0] = 1e9;
ans[s] = f[s][0] = 1e9;
if(vis[s]) mav[s][0] = 0 , miv[s][0] = 0;
}
for (int d = 0; d < k; ++d) {
for (int s = 0; s < (1 << k); ++s) {
mav[s][d + 1] = max(mav[s][d] , mav[s ^ (1 << d)][d] + (1 << d));
miv[s][d + 1] = min(miv[s][d] , miv[s ^ (1 << d)][d] + (1 << d));
f[s][d + 1] = min(f[s][d] , min(f[s ^ (1 << d)][d] , miv[s ^ (1 << d)][d] + (1 << d) - mav[s][d]));
ans[s] = min(ans[s] , f[s][d + 1]);
}
}
for (int s = 0; s < (1 << k); ++s) write(ans[s] , ' ');
return 0;
}