独钓寒江雪
题目背景:
分析:哈希 + 树型DP
从这道题上感觉到了深深的绝望······在OJ上一直都是12msWA,一直不知道怎么搞的,造的500000随机数据怎么跑怎么过······拍了几百组都没有锅,最后突然奇想造了条链,然后炸了······然后改小数据范围10000WA了,100WA了,10WA了,5WA了······然后手调一下发现我的hash函数和size有关,然后找到重心换根后没有更新过size······然后就这样炸掉了,随机数据好像大部分都是以1为根,竟然就活的上好······不说了
讲题,首先我们对于独立点集的求取应该非常简单吧,定义f[i][0/1]表示i(不是/是)极寒点的方案数,显然f[i][0]为i所有的儿子v的(f[v][0] + f[v][1])之积,f[i][1]为所有f[v][0]之积,考虑如何保证结构,显然,我们会想到树hash来维护同构,那么我们只需要定义hash函数,若hash[i] == hash[j]则表示两者结构相同,那么只要定一个能够保证这个条件的又不易冲突的hash函数即可,并且我们DP的开始位置一定要是重心,因为其他点是可能变化的,但是重心肯定还是那两个,再者,如果出现了子树完全同构的情况,比如这种子树有m个,可行的构造方案n种那么这一块的总方案有C(n + m - 1, m)种,然后根据乘法原理就可以直接DP了。
Source:
/*
created by scarlyw
*/
#include <cstdio>
#include <string>
#include <algorithm>
#include <cstring>
#include <iostream>
#include <cmath>
#include <cctype>
#include <vector>
#include <set>
#include <queue>
const int MAXN = 500000 + 10;
const long long mod = 1000000000 + 7;
const unsigned long long base = 233;
int n, x, y, c1, c2, ans;
long long inv[MAXN], size[MAXN], f[MAXN][2];
unsigned long long hash[MAXN], hash_pow[MAXN];
std::vector<int> edge[MAXN];
inline void add_edge(int x, int y) {
edge[x].push_back(y), edge[y].push_back(x);
}
inline void pre_work() {
inv[1] = 1, hash_pow[0] = 1;
for (int i = 2; i <= n; ++i)
inv[i] = (long long)(-mod / i + mod) * inv[mod % i] % mod;
for (int i = 1; i <= n; ++i) hash_pow[i] = hash_pow[i - 1] * base;
}
inline void read_in() {
scanf("%d", &n);
for (int i = 1; i < n; ++i) scanf("%d%d", &x, &y), add_edge(x, y);
}
inline void dfs_root(int cur, int fa) {
size[cur] = 1;
bool flag = true;
for (int p = 0; p < edge[cur].size(); ++p) {
int v = edge[cur][p];
if (v != fa) {
dfs_root(v, cur), size[cur] += size[v];
if (2 * size[v] > n) flag = false;
}
}
if (size[cur] * 2 < n) flag = false;
if (flag) (c1 == 0 ? c1 = cur : c2 = cur);
}
inline bool comp(const int &a, const int &b) {
return hash[a] < hash[b];
}
inline long long c(long long n, int m) {
long long ans = 1;
n %= mod;
for (int i = 1; i <= m; ++i) ans = ans * (n + 1LL - i) % mod * inv[i] % mod;
return ans;
}
inline void dfs(int cur, int fa) {
static int stack[MAXN];
int top = 0, j, v;
hash[cur] = hash_pow[0], size[cur] = 1;
for (int p = 0; p < edge[cur].size(); ++p) {
int v = edge[cur][p];
if (v != fa) {
dfs(v, cur), size[cur] += size[v];
hash[cur] += hash_pow[size[v]] * hash[v];
}
}
for (int p = 0; p < edge[cur].size(); ++p) {
int v = edge[cur][p];
if (v != fa) stack[++top] = v;
}
f[cur][0] = f[cur][1] = 1;
std::sort(stack + 1, stack + top + 1, comp);
for (int i = 1; i <= top; i = j) {
for (v = stack[i], j = i + 1; j <= top &&
hash[stack[i]] == hash[stack[j]]; ++j);
f[cur][0] = f[cur][0] * c(j - i - 1 + f[v][0] + f[v][1], j - i) % mod;
f[cur][1] = f[cur][1] * c(j - i - 1 + f[v][0], j - i) % mod;
}
}
inline void solve() {
read_in(), dfs_root(1, 1), pre_work();
(c2 ? (dfs(c1, c2), dfs(c2, c1)) : (dfs(c1, c1)));
if (c2) {
if (hash[c1] != hash[c2]) {
ans = (f[c1][0] * f[c2][0] + f[c1][1] * f[c2][0] +
f[c1][0] * f[c2][1]) % mod;
} else ans = (f[c1][0] * f[c2][1] + c(f[c1][0] + 1, 2)) % mod;
} else ans = (f[c1][0] + f[c1][1]) % mod;
printf("%d", ans);
}
int main() {
solve();
return 0;
}