您的位置:首页 > Web前端

[分治][Trie][prufer数列] 51Nod 1601 完全图的最小生成树计数

2018-03-07 21:14 549 查看

SolutionSolution

考虑从高位到低位枚举。

显然是把相同的放在一边,不同的找到权值最小的连边,这个可以TrieTrie。

这样分治下去,最后得到一个没有限制的联通块,贡献就是sizesize−2sizesize−2。

因为偷懒写了vectorvector,还必须得预处理nn−2nn−2这样的东西qwq。。跑得巨慢。。

复杂度是O(nlog2w)O(nlog2⁡w)。

如果TrieTrie和分治一起写的话可能是可以O(nlogw)O(nlog⁡w)的啦。。

#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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: