51nod_1677:treecnt
题目是求一棵n节点树中对于C(n,k)颗子树,每棵子树为在n个节点中选不同的k个节点作为树的边界点,这样的所有子树共包含多少条边。
问题可以转化一下,对每一条边,不同的子树中可能包含可能不包含这条边,显然,只有子树那k个节点在该边的两侧均有分布时该边才被包含在子树中。所有边的被包含次数的和,即为answer。对于一条边的被包含次数,设该边两侧分别有a,b个节点,那么,该边被包含的次数为C(a+b,k)-C(a,k)-C(b,k)(也可以借助母函数函数求C(a,i)*C(b,k-i),i从1到min{a,b,k-1},结果一样)。
//dfs写的太搓了,调了半天才好。。。
- #include<bits/stdc++.h>
- using namespace std;
- typedef long long LL;
- const LL mod=1e9+;
- const LL M=1e5+;
- LL fac[]; //阶乘
- LL inv_of_fac[]; //阶乘的逆元
- LL qpow(LL x,LL n)
- {
- LL ret=;
- for(; n; n>>=)
- {
- if(n&) ret=ret*x%mod;
- x=x*x%mod;
- }
- return ret;
- }
- void init()
- {
- fac[]=;
- for(int i=; i<=M; i++)
- fac[i]=fac[i-]*i%mod;
- inv_of_fac[M]=qpow(fac[M],mod-);
- for(int i=M-; i>=; i--)
- inv_of_fac[i]=inv_of_fac[i+]*(i+)%mod;
- }
- LL C(LL a,LL b)
- {
- if(b>a) return ;
- if(b==) return ;
- return fac[a]*inv_of_fac[b]%mod*inv_of_fac[a-b]%mod;
- }
- /////////////////////////////////////////////////////////////
- vector<int> adj[M];
- int vis[M];
- LL n,k,ans,du[M],hh;
- void init1()
- {
- ans=;
- memset(vis,,sizeof(vis));
- memset(du,,sizeof(du));
- du[]=n;
- hh=C(n,k);
- for(int i=; i<=n; i++)
- adj[i].clear();
- }
- LL dfs(int s)
- {
- if(adj[s].size()==&&s!=) return du[s]=;
- if(du[s]&&s!=) return du[s];
- vis[s]=;
- LL ret,cnt=;
- for(int i=; i<adj[s].size(); i++)
- {
- if(!vis[adj[s][i]])
- {
- // printf("%d -> %d\n",s,adj[s][i]);
- cnt+=dfs(adj[s][i]);
- ans=(ans+hh-C(dfs(adj[s][i]),k)-C(n-dfs(adj[s][i]),k))%mod;
- }
- }
- return du[s]=cnt+;
- }
- int main()
- {
- init();
- while(~scanf("%lld%lld",&n,&k))
- {
- init1();
- for(int i=; i<n; i++)
- {
- LL u,v;
- scanf("%d%d",&u,&v);
- adj[u].push_back(v);
- adj[v].push_back(u);
- }
- dfs();
- // for(int i=1; i<=n; i++)
- // printf("%d:%lld=========\n",i,du[i]);
- // for(int i=1; i<=n; i++)
- // {
- // printf("i=%d:\n",i);
- // for(int j=0; j<adj[i].size(); j++)
- // printf("%d ",adj[i][j]);
- // puts("");
- // }
- printf("%lld\n",(ans+mod)%mod);
- }
- }
// 2017.8.15 更
回头翻一下之前自己写的博客,发现连个dfs都写这么挫,就算这样居然也有人看。重新改了一下代码贴在下面。
- #include<bits/stdc++.h>
- using namespace std;
- typedef long long LL;
- const LL mod=1e9+;
- const LL M=1e5+;
- LL fac[M+]; //阶乘
- LL inv_of_fac[M+]; //阶乘的逆元
- LL qpow(LL x,LL n)
- {
- LL ret=;
- for(; n; n>>=)
- {
- if(n&) ret=ret*x%mod;
- x=x*x%mod;
- }
- return ret;
- }
- void init()
- {
- fac[]=;
- for(int i=; i<=M; i++)
- fac[i]=fac[i-]*i%mod;
- inv_of_fac[M]=qpow(fac[M],mod-);
- for(int i=M-; i>=; i--)
- inv_of_fac[i]=inv_of_fac[i+]*(i+)%mod;
- }
- LL C(LL a,LL b)
- {
- if(b>a) return ;
- if(b==) return ;
- return fac[a]*inv_of_fac[b]%mod*inv_of_fac[a-b]%mod;
- }
- /////////////////////////////////////////////////////////////
- vector<int> adj[M];
- LL n,k,ans,hh;
- void init1()
- {
- ans=;
- hh=C(n,k);
- for(int i=; i<=n; i++)
- adj[i].clear();
- }
- LL dfs(int s,int pre)
- {
- LL ret=;
- for(int i=; i<adj[s].size(); i++)
- {
- if(adj[s][i]==pre) continue;
- LL t=dfs(adj[s][i],s);
- ret+=t;
- ans=(ans+hh-C(t,k)-C(n-t,k))%mod;
- }
- return ret;
- }
- int main()
- {
- init();
- while(~scanf("%lld%lld",&n,&k))
- {
- init1();
- for(int i=; i<n; i++)
- {
- LL u,v;
- scanf("%d%d",&u,&v);
- adj[u].push_back(v);
- adj[v].push_back(u);
- }
- dfs(,-);
- printf("%lld\n",(ans+mod)%mod);
- }
- }
51nod_1677:treecnt的更多相关文章
- treecnt
treecnt ﹡ LH (命题人) 基准时间限制:1 秒 空间限制:131072 KB 分值: 40 给定一棵n个节点的树,从1到n标号.选择k个点,你需要选择一些边使得这k个点通过选择 ...
- 树上统计treecnt(dsu on tree 并查集 正难则反)
题目链接 dalao们怎么都写的线段树合并啊.. dsu跑的好慢. \(Description\) 给定一棵\(n(n\leq 10^5)\)个点的树. 定义\(Tree[L,R]\)表示为了使得\( ...
- [洛谷U40581]树上统计treecnt
[洛谷U40581]树上统计treecnt 题目大意: 给定一棵\(n(n\le10^5)\)个点的树. 定义\(Tree[l,r]\)表示为了使得\(l\sim r\)号点两两连通,最少需要选择的边 ...
- 1677 treecnt(贡献)
1677 treecnt 基准时间限制:1 秒 空间限制:131072 KB 分值: 40 难度:4级算法题 给定一棵n个节点的树,从1到n标号.选择k个点,你需要选择一些边使得这k个点通过选择的边联 ...
- treecnt 算法马拉松20(告别美国大选及卡斯特罗)
treecnt 基准时间限制:1 秒 空间限制:131072 KB 给定一棵n个节点的树,从1到n标号.选择k个点,你需要选择一些边使得这k个点通过选择的边联通,目标是使得选择的边数最少. 现需要计算 ...
- 51Nod 1677 treecnt
一道比较基础的计数题,还是一个常用的单独计算贡献的例子. 首先看题目和范围,暴力枚举肯定是不可行的,而且\(O(n\ logn)\)的算法貌似很难写. 那我们就来想\(O(n)\)的吧,我们单独考虑每 ...
- 51nod 1677 treecnt(思维)
题意: 给定一棵n个节点的树,从1到n标号.选择k个点,你需要选择一些边使得这k个点通过选择的边联通,目标是使得选择的边数最少. 现需要计算对于所有选择k个点的情况最小选择边数的总和为多少. 考虑每条 ...
- 【51nod1677】treecnt(树上数学题)
点此看题面 大致题意: 给你一个节点从1~n编号的树,让你从中选择k个节点并通过选择的边联通,且要使选择的边数最少,让你计算对于所有选择k个节点的情况最小选择边数的总和. 题解 这道题乍一看很麻烦:最 ...
- 【计数】51nod1677 treecnt
要将答案看做是小问题的贡献和 Description 给定一棵n个节点的树,从1到n标号.选择k个点,你需要选择一些边使得这k个点通过选择的边联通,目标是使得选择的边数最少. 现需要计算对于所有选择k ...
随机推荐
- 安卓餐厅点餐系统---针对浩然android工作室的一个小白的分析
昨天刚把浩然android工作室的下载下来了,为了研究下点餐系统的架构,更好的完成手中的项目,便写出一个分析报告(小白的分析,忘见谅!) 本项目app主要用于餐厅无线订餐使用,功能突出餐厅的订餐需求, ...
- Day1 - Python基础1 Python介绍、基本语法、流程控制习题集
1.打印Hello World! print("Hello World!") 或 name="你好,世界!" print(name) 2.声明变量:打印name ...
- Vue基础概念,学习环境等
前提: 你已有 HTML.CSS 和 JavaScript 中级前端知识. 概念: Vue.js(读音 /vjuː/,类似于 view) 是一套构建用户界面的渐进式框架.与其他重量级框架不同的是,Vu ...
- webpack 插件拾趣 (1) —— webpack-dev-server
结束了一季的忙碌,我这封笔已久的博客也终究该从春困的咒印中复苏,想来写些实用易读的作为开篇,自然是最好不过. 新开个 webpack 插件/工具介绍的文章系列,约莫每周更新一篇篇幅适中的文章聊以共勉, ...
- python基础之字典dict和集合set
作者:tongqingliu 转载请注明出处:http://www.cnblogs.com/liutongqing/p/7043642.html python基础之字典dict和集合set 字典dic ...
- BOM API
原文链接http://www.jb51.net/article/55851.htm 我们都知道, javascript 有三部分构成,ECMAScript,DOM和BOM,根据宿主(浏览器)的不同,具 ...
- 【转载】Static 关键字的作用
原始日期:2016-07-16 17:53 一 普通的static关键字 1. 静态全局变量 在全局变量前,加上关键字static,该变量就被定义成为一个静态全局变量.我们先举一个静态全局变 ...
- phpcms和php格式化时间戳
用PHPCMS V9 建站时,经常会用到时间标签,它是通用标签调用-日期时间格式化,适用全站. 一.日期时间格式化显示: a\标准型:{date('Y-m-d H:i:s', $rs['inputti ...
- 基于node.js制作爬虫教程
前言:最近想学习node.js,突然在网上看到基于node的爬虫制作教程,所以简单学习了一下,把这篇文章分享给同样初学node.js的朋友. 目标:爬取 http://tweixin.yueyishu ...
- linux下安装telnet
1:yum install telnet-server 2:编辑设置 /etc/xinetd.d/telnet ,将disable= yes设置成disable= no 3:service xine ...