题解 [CF1446C] Xor Tree

传送门

这都什么神仙题

可以用trie树按题意建图,但并没有什么用
正解考虑一个性质:
我们如何check一个序列是不是good sequence呢?
一个性质是依据最高有效位是0还是1将原序列分为两个集合 \(s_0\)\(s_1\)
于是仅当 \(|s_0|\geqslant 2\) 并且 \(|s_1|\geqslant 2\) 时原序列是good sequence
证明考虑一个点肯定会向(如果有)最高位与自己相同的点连边
于是当上面情况出现时原图会分成至少两个不连通的部分
所以令 \(f(s)\) 为集合 \(s\) 中能形成的最长good sequence长度

\[f(s)=\begin{cases}f(s_0)&s_1=\varnothing\\ f(s_1)&s_0=\varnothing\\ max(f(s_0), f(s_1))+1&other\end{cases} \]

递归做即可

Code:
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 200010
#define ll long long
//#define int long long

char buf[1<<21], *p1=buf, *p2=buf;
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf, 1, 1<<21, stdin)), p1==p2?EOF:*p1++)
inline int read() {
	int ans=0, f=1; char c=getchar();
	while (!isdigit(c)) {if (c=='-') f=-f; c=getchar();}
	while (isdigit(c)) {ans=(ans<<3)+(ans<<1)+(c^48); c=getchar();}
	return ans*f;
}

int n;
int a[N];

int solve(int u, int l, int r) {
	if (u<0) return r-l+1;
	int mid=l;
	while (mid<=r && !(a[mid]&(1<<u))) ++mid;
	if (mid==l || mid>r) return solve(u-1, l, r);
	else return max(solve(u-1, l, mid-1), solve(u-1, mid, r))+1;
}

signed main()
{
	n=read();
	for (int i=1; i<=n; ++i) a[i]=read();
	sort(a+1, a+n+1);
	printf("%d\n", n-solve(30, 1, n));

	return 0;
}
posted @ 2021-11-03 16:21  Administrator-09  阅读(2)  评论(0编辑  收藏  举报