[分治][Trie][prufer数列] 51Nod 1601 完全图的最小生成树计数
2018-03-07 21:14
549 查看
SolutionSolution
考虑从高位到低位枚举。显然是把相同的放在一边,不同的找到权值最小的连边,这个可以TrieTrie。
这样分治下去,最后得到一个没有限制的联通块,贡献就是sizesize−2sizesize−2。
因为偷懒写了vectorvector,还必须得预处理nn−2nn−2这样的东西qwq。。跑得巨慢。。
复杂度是O(nlog2w)O(nlog2w)。
如果TrieTrie和分治一起写的话可能是可以O(nlogw)O(nlogw)的啦。。
#include <bits/stdc++.h> #define show(x) cerr << #x << " = " << x << endl using namespace std; typedef long long ll; typedef pair<int, int> pairs; const int N = 101010; const int M = 3030303; const int K = 30; const int MOD = 1000000007; inline char get(void) { static char buf[100000], *S = buf, *T = buf; if (S == T) { T = (S = buf) + fread(buf, 1, 100000, stdin); if (S == T) return EOF; } return *S++; } template<typename T> inline void read(T &x) { static char c; x = 0; int sgn = 0; for (c = get(); c < '0' || c > '9'; c = get()) if (c == '-') sgn = 1; for (; c >= '0' && c <= '9'; c = get()) x = x * 10 + c - '0'; if (sgn) x = -x; } int ch[M][2]; int sz[M]; int tcnt, root; ll val; int cnt; int n; int pwn ; vector<int> a; inline pairs operator ^(int x, pairs y) { return pairs(x ^ y.first, y.second); } inline int pwr(int a, int b) { int c = 1; while (b) { if (b & 1) c = (ll)c * a % MOD; b >>= 1; a = (ll)a * a % MOD; } return c; } inline void init(void) { tcnt = root = 1; } inline void insert(int u, int x) { ++sz[u]; for (int i = K; ~i; i--) { int &v = ch[u][x >> i & 1]; if (v == 0) v = ++tcnt; u = v; ++sz[u]; } } inline pairs query(int u, int x, int d) { if (d < 0) return pairs(0, sz[u]); int y = x >> d & 1; if (ch[u][y]) return query(ch[u][y], x, d - 1); return (1 << d) ^ query(ch[u][y ^ 1], x, d - 1); } inline void watch(vector<int> x) { for (int u: x) cerr << u << ' '; cerr << endl; } inline void divAndConq(int u, vector<int> &b, int d) { vector<int> b0, b1; if (u == 0) return; if (d < 0) { int n = b.size(); if (n >= 2) cnt = (ll)cnt * pwn % MOD; return; } b0.clear(); b1.clear(); for (int x: b) if (x >> d & 1) b1.push_back(x); else b0.push_back(x); //watch(b0); watch(b1); //cerr << b0.size() << ' ' << b1.size() << endl; ll w = 1ll << 60, c; if (b0.size() < b1.size()) { if (b0.size() == 0) w = 0, c = 1; for (int x: b0) { pairs res = (1 << d) ^ query(ch[u][1], x, d - 1); if (res.first == w) { c += res.second; } else if (res.first < w) { w = res.first; c = res.second; } } } else { if (b1.size() == 0) w = 0, c = 1; for (int x: b1) { pairs res = (1 << d) ^ query(ch[u][0], x, d - 1); if (res.first == w) { c += res.second; } else if (res.first < w) { w = res.first; c = res.second; } } } val += w; cnt = (ll)cnt * c % MOD; divAndConq(ch[u][0], b0, d - 1); divAndConq(ch[u][1], b1, d - 1); } int main(void) { freopen("1.in", "r", stdin); freopen("1.out", "w", stdout); read(n); a.resize(n); init(); for (int i = 2; i <= n; i++) pwn[i] = pow(i, i - 2); val = 0; cnt = 1; for (int i = 0; i < n; i++) { read(a[i]); insert(root, a[i]); } divAndConq(root, a, K); printf("%lld\n%d\n", val, cnt); return 0; }
相关文章推荐
- 51nod 1601 完全图的最小生成树计数 Trie+kruskal
- 51nod 1601 完全图的最小生成树计数 字典树+最小生成树
- 51Nod 1601 完全图的最小生成树计数
- 51nod 算法马拉松22 完全图的最小生成树计数 【Trie树+图论】
- 51Nod1601 完全图的最小生成树计数
- [XOR最小生成树 分治 Trie || Prim 堆] BNUOJ 52318 Be Friends
- 51Nod1601 完全图的最小生成树计数
- 【Kruskal+DFS】BZOJ1016(JSOI2008)[最小生成树计数]题解
- 【BZOJ】1016 生成树计数 最小生成树 Maxtrix-Tree定理 生成树计数 搜索
- 【BZOJ 1016】 [JSOI2008]最小生成树计数(matrix-tree定理做法)
- [动态最小生成树 CDQ分治] SnackDown 2017 Online Elimination Round #GQUERY Game Revisited
- [矩阵树定理 模板题] BZOJ 1016 [JSOI2008]最小生成树计数 & HDU 4408 Minimum Spanning Tree
- 1016: [JSOI2008]最小生成树计数
- 关于问题的分析小结(1)-----bzoj1016最小生成树计数
- 【最小生成树】BZOJ1016: [JSOI2008]最小生成树计数
- 51nod 1212 无向图最小生成树 (Kruskal)
- 51NOD 1222 最小公倍数计数 [莫比乌斯反演 杜教筛]
- BZOJ1016 最小生成树计数
- 【BZOJ5119】【CTT2017】生成树计数 DP 分治FFT 斯特林数
- 【BZOJ 1016】 1016: [JSOI2008]最小生成树计数 (DFS|矩阵树定理)