bzoj3162 独钓寒江雪

独钓寒江雪

题目背景:

bzoj3162

分析:哈希 + 树型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;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值