Live2D

Solution -「AT 3913」XOR Tree

Description

  Link.

  给定一棵树,边 (u,v) 有边权 w(u,v)。每次操作可以使一条简单路径上的边权异或任意非负整数。求最少的操作次数使得所有边边权为 0

  n105w(u,v)<16

Solution

  好妙的题 www。

  定义一个点的点权 valu 为其所有邻接边边权的异或和,即 valu=(u,v)Ew(u,v)。一个至关重要的发现:所有边权为零等价于所有点权为零

  左推右是显然的;右推左,数归,考虑到叶子的边权等于点权,所以去掉所有叶子仍满足,得证。

  再考虑一次操作,除路径两端的点,每个点有两条邻接边被异或了同一个数,所以这些点的点权不变

  非常 amazing 啊,这样一来问题就从树上剥离了——给一堆数,每次任选两个数异或同一个非负整数,求把这些数变成 0 的最小操作次数。


  首先,若存在 uv,valu=valv,显然应该用一次操作处理掉它们。问题进一步转化——给一个值域在 [0,16) 的集合(无重复元素),求把这些数变成 0 的最小操作次数。

  鉴于 16=24,考虑状压。设 f(S) 为处理集合 S 的最小操作次数。显然对于 S 内元素异或和不为 0f(S),有 f(S)=+。接下来想想对于 S0 的转移:

f(S)=minTS{count(S)1,f(T)+f(ST)}

  其中,前一项是暴力两两异或,后者即分别处理两个子集。

  设 w(u,v) 的上限 W=2k, kN,复杂度 O(3k+n)

Code

#include <cstdio>
#include <cstring>

const int MAXN = 1e5, INF = 0x3f3f3f3f;
int n, val[MAXN + 5], cnt[16], f[1 << 16], xsum[1 << 16];

inline void chkmin ( int& a, const int b ) { if ( b < a ) a = b; }

int main () {
	scanf ( "%d", &n );
	for ( int i = 1, u, v, w; i < n; ++ i ) {
		scanf ( "%d %d %d", &u, &v, &w );
		val[u] ^= w, val[v] ^= w;
	}
	int ans = 0, S = 0;
	for ( int i = 0; i < n; ++ i ) ++ cnt[val[i]];
	for ( int i = 1; i < 16; ++ i ) {
		S |= ( cnt[i] & 1 ) << i >> 1;
		ans += cnt[i] >> 1;
	}
	for ( int i = 1; i < 1 << 15; ++ i ) {
		for ( int j = 0; j < 15; ++ j ) {
			if ( ( i >> j ) & 1 ) {
				++ f[i], xsum[i] ^= j + 1;
			}
		}
		-- f[i];
	}
	for ( int s = 0; s < 1 << 15; ++ s ) {
		if ( xsum[s] ) continue;
		for ( int t = s; ; t = ( t - 1 ) & s ) {
			if ( ! xsum[t] && ! xsum[s ^ t] ) chkmin ( f[s], f[t] + f[s ^ t] );
			if ( ! t ) break;
		}
	}
	printf ( "%d\n", ans + f[S] );
	return 0;
}
posted @   Rainybunny  阅读(110)  评论(0编辑  收藏  举报
编辑推荐:
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示