CF1553H XOR and Distance

猜猜这篇过多久才会被码农教程爬qwq。

好高妙啊。

考虑按位考虑。定义 f(x,d) , 表示所有与 x 最多只有前 d 位不同的所有 ai 异或 x 的最小差。

考虑 d 增加 1 , 那么会多上一些 d+1 位与 x 不同的数。

三种情况,答案在原集合,新集合,各占一个。

原集合容易处理,新集合就是 f(y,d)+2d ,其中 y 是只有 d+1 位与 x 不同的数。

各占一个的情况,注意到新集合的数异或 x 的结果一定大于原集合的结果。因此维护 mxv(x,d) / miv(x,d) 表示所有与 x 只有前 d 位不同的所有 ai 异或的最大/小值。

那么各占一个的贡献就是 miv(y,d)+2dmxv(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;
}
posted @   Reanap  阅读(31)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示