bzoj

description

你要给一个树上的每个点黑白染色,要求白点不相邻。求本质不同的染色方案数。
两种染色方案本质相同当且仅当对树重新标号后对应节点的颜色相同。
\(n\le 5\times10^5\)

sol

首先考虑没有本质相同那个限制怎么做。
直接设\(f_{i,0/1}\)表示\(i\)点染成黑色/白色时子树内的方案数。
转移很简单:\(f_{i,0}=\prod_j (f_{j,0}+f_{j,1}),f_{i,1}=\prod_j f_{j,0}\)。

先在问题在于本质不同。那么如果重新标号之后同构的话方案数就会多算。
考虑重新标号后重心不会变,于是以重心为根处理子树。如果有两个重心就新建一个点连接这两个点,在输出方案的时候讨论一下即可。
在\(dp\)的时候,对于一个点\(i\)的若干个同构的子树,应该要一起计算贡献,设这种子树染色的方案数是\(x\)(就是\(dp\)值),这样的子树一共有\(k\)棵,那么这就是一个可重组合,方案数为\(\binom{x+k-1}{k}\)。
虽然\(x\)可能会很大,但是显然\(k\)是\(O(n)\)的,所以组合数暴力计算即可。

树\(Hash\)要写对啊qwq。

code

#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
int gi(){int x=0,w=1;char ch=getchar();while ((ch<'0'||ch>'9')&&ch!='-') ch=getchar();if (ch=='-') w=0,ch=getchar();while (ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();return w?x:-x;
}
#define ull unsigned long long
const int N = 5e5+5;
const int mod = 1e9+7;
const ull base1 = 20020415;
const ull base2 = 20011118;
int n,inv[N],to[N<<1],nxt[N<<1],head[N],cnt,sz[N],w[N],root,rt1,rt2,fg,f[2][N],tmp[N];
ull hsh[N];
void link(int u,int v){to[++cnt]=v;nxt[cnt]=head[u];head[u]=cnt;
}
void getroot(int u,int fa){sz[u]=1;w[u]=0;for (int e=head[u];e;e=nxt[e])if (to[e]!=fa){getroot(to[e],u);sz[u]+=sz[to[e]];w[u]=max(w[u],sz[to[e]]);}w[u]=max(w[u],n-sz[u]);if (w[u]<w[root]) root=u;
}
int C(int n,int m){int res=1;for (int i=n-m+1;i<=n;++i) res=1ll*res*i%mod;for (int i=1;i<=m;++i) res=1ll*res*inv[i]%mod;return res;
}
bool cmp(int i,int j){return hsh[i]<hsh[j];}
void dfs(int u,int fa){sz[u]=f[0][u]=f[1][u]=1;for (int e=head[u];e;e=nxt[e])if (to[e]!=fa) dfs(to[e],u),sz[u]+=sz[to[e]];int len=0;for (int e=head[u];e;e=nxt[e])if (to[e]!=fa) tmp[++len]=to[e];sort(tmp+1,tmp+len+1,cmp);for (int i=1,j=1;i<=len;i=j){while (j<=len&&hsh[tmp[j]]==hsh[tmp[i]]) ++j;f[0][u]=1ll*f[0][u]*C(f[0][tmp[i]]+f[1][tmp[i]]+j-i-1,j-i)%mod;f[1][u]=1ll*f[1][u]*C(f[0][tmp[i]]+j-i-1,j-i)%mod;}hsh[u]=base2*len+sz[u];for (int i=1;i<=len;++i)hsh[u]=(hsh[u]*base1)^hsh[tmp[i]];
}
int main(){n=gi();inv[0]=inv[1]=1;for (int i=2;i<=n;++i) inv[i]=1ll*inv[mod%i]*(mod-mod/i)%mod;for (int i=1;i<n;++i){int u=gi(),v=gi();link(u,v),link(v,u);}w[0]=n;getroot(1,0);getroot(root,0);for (int e=head[root],lst=0;e;lst=e,e=nxt[e])if (sz[to[e]]*2==n){++n;if (e==head[root]) head[root]=nxt[e];else nxt[lst]=nxt[e];for (int i=head[to[e]],Lst=0;i;Lst=i,i=nxt[i])if (to[i]==root){if (i==head[to[e]]) head[to[e]]=nxt[i];else nxt[Lst]=nxt[i];break;}link(n,root);link(root,n);link(n,to[e]);link(to[e],n);rt1=root;rt2=to[e];root=n;fg=1;break;}dfs(root,0);if (!fg) printf("%d\n",(f[0][root]+f[1][root])%mod);else if (hsh[rt1]==hsh[rt2]) printf("%d\n",(f[0][root]-C(f[1][rt1]+1,2)+mod)%mod);else printf("%d\n",(1ll*f[0][rt1]*f[0][rt2]+1ll*f[0][rt1]*f[1][rt2]+1ll*f[1][rt1]*f[0][rt2])%mod);return 0;
}

转载于:https://www.cnblogs.com/zhoushuyu/p/9295759.html

[BZOJ3162]独钓寒江雪相关推荐

  1. 洛谷4895 BZOJ3162 独钓寒江雪 树形dp 树哈希

    题目链接 题意: 给定一棵无根树,求其中本质不同的独立集的个数.独立集就是一个集合中的点之间都没有边直接相连.n<=5e5n<=5e5n<=5e5,对1e9+71e9+71e9+7取 ...

  2. bzoj3162 独钓寒江雪(树形dp+Hash)

    就是求无根树的本质不同的独立集个数.如果不考虑本质不同,则有树形dp. 考虑本质不同,就要考虑无根树的同构,可以用hash来搞.具体题解见:portal 我的hash真是冲突到死[再见],hash值最 ...

  3. BZOJ3162 独钓寒江雪【无根树同构问题】

    题目描述: 给定一棵无根树,求其中本质不同的独立集的个数. n<=500000 题目分析: 如果任选一点作根,那么它选1的情况和它选0的情况有可能是本质相同的. 但如果选重心作根(如果有两个重心 ...

  4. Noip前的大抱佛脚----赛前任务

    赛前任务 tags:任务清单 前言 现在xzy太弱了,而且他最近越来越弱了,天天被爆踩,天天被爆踩 题单不会在作业部落发布,所以可(yi)能(ding)会不及时更新 省选前的练习莫名其妙地成为了Noi ...

  5. BZOJ 3162 独钓寒江雪(树同构计数)

    给定一棵无根树,求其中本质不同的独立集的个数. 无根树同构. 转化成以重心为根的有根树,如果重心有两个,就在这两个重心之间插入一个点与这两个重心连边,这个点作为新的重心. 然后就成了有根树同构过程树形 ...

  6. BZOJ 3162: 独钓寒江雪 树的同构 + 组合 + 计数

    Description Input Output 求一棵树编号序列不同的方案数: 令 $f[u],g[u]$ 分别表示 $u$ 选/不选 的方案数. 则 $f[u]=\prod_{v\in son[u ...

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

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

  8. bzoj 3162: 独钓寒江雪 树哈希+树形dp

    题意 给出一棵无标号无根树,问本质不同的最大独立集数量.答案模1e9+7. n<=500000 分析 对于一般的情况,我们可以先找出树的重心作为根,然后进行树形dp.这样做有什么好处呢?通过根的 ...

  9. 使用openpyxl去操作Excel表格

    对表格的数据写操作: from openpyxl import Workbook wb=Workbook()w1=wb.create_sheet('index',0) # w1["E4&qu ...

  10. C# 操作Sql Server 学习总结

    C#中产生SQL语句的几种方式 (1)拼接产生SQL语句: string sql = "insert into czyb(yhm,mm,qx) values('" + txtNam ...

最新文章

  1. java任何封闭实例都不是java_《java并发编程实战》读书笔记3--对象的组合
  2. 从零开始学习jQuery (六) AJAX快餐
  3. 【原创】FPGA (Verilog/NIOS II/Microblaze) 编程小提醒
  4. [codevs 1922] 骑士共存问题
  5. NumPy学习笔记 一
  6. 01.java内存模型
  7. EJB是什么?EJB的概念分析与理解(copy)
  8. 未获取root手机抓包方法
  9. 如何理解 Graph Convolutional Network(GCN)?
  10. 写在前面(ShenYu)
  11. Java doc或docx转pdf文件预览
  12. mysql 富文本 字段,富文本引起MYSQL出错
  13. 如何找出当前活动桌面背景图像的位置/路径(Ubuntu 18.04,GNOME)?
  14. 小丁在加班之JVM优化-内存结构
  15. 【题解】P2678 [NOIP2015 提高组] 跳石头
  16. 指令、微程序、微指令、微命令、微操作之间的联系
  17. 全部驳回?元宇宙商标申请被国家知识产权局“劝退”
  18. wordpress采集插件-wordpress关键词插件-wordpress百度推送插件-wordpress蜘蛛统计分析插件
  19. MACOS 12以上系统如何安装HP打印机驱动
  20. PMP的一些概念与计算公式

热门文章

  1. 计算机应用班级口号,适用于班级的口号大全
  2. hexo文章中插入图片
  3. Rosalind第11题:Mortal Fibonacci Rabbits
  4. [译]第一章:什么是管理
  5. SubsamplingScaleImageView + Glide显示网络超大图片
  6. 产品经理的职责和分类
  7. Java邮件发送(实名发送和匿名发送)
  8. vue子组件的使用和事件传递
  9. DevicePolicyManagerService之DeviceOwner和ProfileOwner
  10. 深度Linux怎样关闭休眠,deepin如何休眠,