独钓寒江雪

题目链接https://www.lydsy.com/JudgeOnline/problem.php?id=3162


题解

首先,如果没有那个本质相同的限制这就是个傻逼题。

直接树形dp就好。

那么如果加上那个限制呢?

我们发现,无论最后怎么本质相同,树的重心一定不变。

故此,从重心开始去重即可。

参考:https://www.cnblogs.com/zhoushuyu/p/9295759.html

代码

#include <bits/stdc++.h>

#define N 500010 

using namespace std;

const int mod = 1000000007 ;

char *p1, *p2, buf[100000];

typedef unsigned long long ll;

ll bs1 = 20021214 ;

ll bs2 = 20030315 ;

#define nc() (p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 100000, stdin), p1 == p2) ? EOF : *p1 ++ )

int rd() {
int x = 0;
char c = nc();
while (c < 48) {
c = nc();
}
while (c > 47) {
x = (((x << 2) + x) << 1) + (c ^ 48), c = nc();
}
return x;
} int n, inv[N], to[N << 1], nxt[N << 1], head[N], tot, sz[N], w[N], root, rt1, rt2, flag, f[2][N], tmp[N]; ll hs[N]; inline void add(int x, int y) {
to[ ++ tot] = y;
nxt[tot] = head[x];
head[x] = tot;
} void getroot(int p, int fa) {
sz[p] = 1;
w[p] = 0;
for (int i = head[p]; i; i = nxt[i]) {
if(to[i] != fa) {
getroot(to[i], p);
sz[p] += sz[to[i]];
w[p] = max(w[p], sz[to[i]]);
}
}
w[p] = max(w[p], n - sz[p]);
if (w[p] < w[root]) {
root = p;
}
} int C(int n, int m) {
int re = 1;
for (int i = n - m + 1; i <= n; i ++ ) {
re = (ll)re * i % mod;
}
for (int i = 1; i <= m; i ++ ) {
re = (ll)re * inv[i] % mod;
}
return re;
} inline bool cmp(int i, int j) {
return hs[i] < hs[j];
} void dfs(int p, int fa) {
sz[p] = f[0][p] = f[1][p] = 1;
for (int i = head[p]; i; i = nxt[i]) {
if (to[i] != fa) {
dfs(to[i], p);
sz[p] += sz[to[i]];
}
}
int len = 0;
for (int i = head[p]; i; i = nxt[i]) {
if (to[i] != fa) {
tmp[ ++ len] = to[i];
}
}
sort(tmp + 1, tmp + len + 1, cmp);
for (int i = 1, j = 1; i <= len; i = j) {
while (j <= len && hs[tmp[j]] == hs[tmp[i]]) {
j ++ ;
}
f[0][p] = (ll)f[0][p] * C(f[0][tmp[i]] + f[1][tmp[i]] + j - i - 1, j - i) % mod;
f[1][p] = (ll)f[1][p] * C(f[0][tmp[i]] + j - i - 1, j - i) % mod;
}
hs[p] = bs2 * len + sz[p];
for (int i = 1; i <= len; i ++ ) {
hs[p] = (hs[p] * bs1) ^ hs[tmp[i]];
}
} int main() {
n = rd();
inv[0] = inv[1] = 1;
for (int i = 2; i <= n; i ++ ) {
inv[i] = (ll)inv[mod % i] * (mod - mod / i) % mod;
}
for (int i = 1; i < n; i ++ ) {
int x = rd(), y = rd();
add(x, y), add(y, x);
}
w[0] = n;
getroot(1, 0);
getroot(root, 0);
for (int i = head[root], last = 0; i; last = i, i = nxt[i]) {
if (sz[to[i]] * 2 == n) {
n ++ ;
if (i == head[root]) {
head[root] = nxt[i];
}
else {
nxt[last] = nxt[i];
}
for (int j = head[to[i]], lst = 0; j; lst = j, j = nxt[j]) {
if (to[j] == root) {
if (j == head[to[i]]) {
head[to[i]] = nxt[j];
}
else {
nxt[lst] = nxt[j];
}
break;
}
}
add(n, root);
add(root, n);
add(n, to[i]);
add(to[i], n);
rt1 = root;
rt2 = to[i];
root = n;
flag = 1;
break;
}
}
dfs(root, 0);
if (!flag) {
cout << (f[0][root] + f[1][root]) % mod << endl ;
}
else if (hs[rt1] == hs[rt2]) {
cout << (f[0][root] - C(f[1][rt1] + 1, 2) + mod) % mod;
}
else {
cout << ((ll)f[0][rt1] * f[0][rt2] + (ll)f[0][rt1] * f[1][rt2] + (ll)f[1][rt1] * f[0][rt2]) % mod << endl ;
}
}

小结:树hash的时候,如果一个模数担心过不去,像我一样开两个就好了233

[bzoj3162]独钓寒江雪_树hash_树形dp的更多相关文章

  1. BZOJ3162 独钓寒江雪(哈希+树形dp)

    数独立集显然是可以树形dp的,问题在于本质不同. 假设已经给树确立了一个根并且找到了所有等效(注意是等效而不是同构)子树,那么对转移稍加修改使用隔板法就行了. 关键在于找等效子树.首先将树的重心(若有 ...

  2. BZOJ_2097_[Usaco2010 Dec]Exercise 奶牛健美操_二分答案+树形DP

    BZOJ_2097_[Usaco2010 Dec]Exercise 奶牛健美操_二分答案+树形DP Description Farmer John为了保持奶牛们的健康,让可怜的奶牛们不停在牧场之间 的 ...

  3. BZOJ_1999_[Noip2007]Core树网的核_单调队列+树形DP

    BZOJ_1999_[Noip2007]Core树网的核_单调队列+树形DP Description 设T=(V, E, W) 是一个无圈且连通的无向图(也称为无根树),每条边带有正整数的权,我们称T ...

  4. 【NOI P模拟赛】仙人掌(圆方树,树形DP)

    题面 n n n 个点, m m m 条边. 1 ≤ n ≤ 1 0 5 , n − 1 ≤ m ≤ 2 × 1 0 5 1\leq n\leq 10^5,n-1\leq m\leq 2\times1 ...

  5. bzoj 1040 [ZJOI2008]骑士(基环外向树,树形DP)

    [题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=1040 [题意] 给一个基环森林,每个点有一个权值,求一个点集使得点集中的点无边相连且权 ...

  6. 洛谷4895 独钓寒江雪 (树哈希+dp+组合)

    qwq 首先,如果是没有要求本质不同的话,那么还是比较简单的一个树形dp 我们令\(dp[i][0/1]\)表示是否\(i\)的子树,是否选\(i\)这个点的方案数. 一个比较显然的想法. \(dp[ ...

  7. 青云的机房组网方案(简单+普通+困难)(虚树+树形DP+容斥)

    题目链接 1.对于简单的版本n<=500, ai<=50 直接暴力枚举两个点x,y,dfs求x与y的距离. 2.对于普通难度n<=10000,ai<=500 普通难度解法挺多 ...

  8. 洛谷AT2046 Namori(思维,基环树,树形DP)

    洛谷题目传送门 神仙思维题还是要写点东西才好. 树 每次操作把相邻且同色的点反色,直接这样思考会发现状态有很强的后效性,没办法考虑转移. 因为树是二分图,所以我们转化模型:在树的奇数层的所有点上都有一 ...

  9. Luogu4630 APIO2018 Duathlon 圆方树、树形DP

    传送门 要求的是一条按顺序经过\(s,t,c\)三个点的简单路径.简单路径的计数问题不难想到点双联通分量,进而使用圆方树进行求解. 首先将原图缩点,对于一个大小为\(size\)的点双联通分量内,在这 ...

随机推荐

  1. JSP大文件分片上传

    核心原理: 该项目核心就是文件分块上传.前后端要高度配合,需要双方约定好一些数据,才能完成大文件分块,我们在项目中要重点解决的以下问题. * 如何分片: * 如何合成一个文件: * 中断了从哪个分片开 ...

  2. 【luoguUVA1316】 Supermarket--普通并查集+贪心

    题目描述 有一个商店有许多批货,每一批货又有N(0<=N<=10^4 )个商品,同时每一样商品都有收益P_iPi​ ,和过期时间D_iDi​ (1<=Pi,,Di <=10^4 ...

  3. jQuery系列(八):jQuery的位置信息

    1.宽度和高度 (1):获取宽度 .width() 描述:为匹配的元素集合中获取第一个元素的当前计算宽度值.这个方法不接受任何参数..css(width) 和 .width()之间的区别是后者返回一个 ...

  4. 2019ICPC上海网络赛 A Lightning Routing I 点分树(动态点分治)+线段树

    题意 给一颗带边权的树,有两种操作 \(C~e_i~w_i\),将第\(e_i\)条边的边权改为\(w_i\). \(Q~v_i\),询问距\(v_i\)点最远的点的距离. 分析 官方题解做法:动态维 ...

  5. Linux Redis的性能展示

    我们可以通过redis-cli 连接上redis ,例如 : redis-cli -h 127.0.0.1 -p 6379 连接上redis,然后通过INFO查看redis的一些信息.我们可以查看一些 ...

  6. 使用<bind>元素创建变量

    在使用模糊查询sql时,如果使用${}进行字符拼接,无法防止sql诸如问题,如果使用concat函数则只对mysql有效果,用Oracle则需要用连接符||,这样在数据库变的时候需要修改,不利于移植. ...

  7. Nginx数据结构之散列表

    1. 散列表(即哈希表概念) 散列表是根据元素的关键码值而直接进行访问的数据结构.也就是说,它通过把关键码值映射到表中一个位置来访问记录, 以加快查找速度.这个映射函数 f 叫做散列方法,存放记录的数 ...

  8. LeetCode 141. 环形链表(Linked List Cycle)

    题目描述 给定一个链表,判断链表中是否有环. 进阶:你能否不使用额外空间解决此题? 解题思路 快慢指针,慢指针一次走一步,快指针一次走两步,若两者相遇则说明有环,快指针无路可走则说明无环. 代码 /* ...

  9. 后盾网lavarel视频项目---Vue项目使用vue-awesome-swiper轮播插件

    后盾网lavarel视频项目---Vue项目使用vue-awesome-swiper轮播插件 一.总结 一句话总结: vue中的插件的使用和js插件的使用一样的简单,只是vue插件的引入过程有些不同 ...

  10. Rocketmq异步发送消息

    package com.bfxy.rocketmq.quickstart; import java.util.List; import org.apache.rocketmq.client.excep ...