http://codeforces.com/contest/1446
C. Xor Tree
题意:给定一个n个数都不相同的数列,每个数和另一个数相连无向边,满足它与另一个数的异或值小于它与其它数的异或值,两个数互相连边算作连一次。要求删去最少的数,使得得到一棵树。
字典树
试一下就能发现不会成环,所以要形成树只要满足只有一对点互相连边。
把所有数都插进Trie里,对于节点 u,它的左子树里的所有节点必定只会与左子树中点相连,所以如果左子树中选择了大于等于2个点,则这两个点必定会形成一条互相的连边。而如果左子树只选一个点,则这个点不会形成互相的连边。
Trie上dp
ans[u]=max(ans[lson(u)]+1,ans[rson(u)]+1)。
如果只有左子树或只有右子树,则 ans[u]=ans[lson(u)]。
如果是叶子,则返回1.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| #include <bits/stdc++.h> #define debug(x) cout << #x << ":\t" << (x) << endl; using namespace std; #define ll long long const int N = 2e7 + 10; const int INF = 0x3f3f3f3f; const ll inf = 0x3f3f3f3f3f3f3f3f; const ll mod = 998244353; int n, ans; int a[N]; int ch[N][2], tot; void ins(int x) { int rt = 0; for (int i = 30; i >= 0; i--) { int bt = (x >> i & 1); if (!ch[rt][bt])ch[rt][bt] = ++tot; rt = ch[rt][bt]; } } int dfs(int u) { if (ch[u][0] && ch[u][1]) { return max(dfs(ch[u][0]) + 1, dfs(ch[u][1]) + 1); } else if (ch[u][0])return dfs(ch[u][0]); else if (ch[u][1])return dfs(ch[u][1]); else { return 1; } } int main() { scanf("%d", &n); for (int i = 1; i <= n; i++)scanf("%d", &a[i]); for (int i = 1; i <= n; i++)ins(a[i]); printf("%d\n", n - dfs(0)); return 0; }
|