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 ...
随机推荐
- Java之进程与线程练习
1.设计一个线程类:创建3个子线程,每个线程分别打印数字,分别睡眠100,200,300ms ->每个执行都是20次 代码: package Homework; //1.设计一个线程类:创建3个 ...
- ajax 动态添加商品列表
<!DOCTYPE html><html> <head> <meta charset="utf-8" /> <title> ...
- orcle自定义类型type/create or replace type
一.type / create or repalce type 区别联系 相同: 可用关键字create type 或者直接用type定义自定义类型, 区别: create type 变量 as ta ...
- JS 点击复制按钮 将文字复制到手机剪贴板
我们在制作移动端网页的时候,经常会遇到这样一个问题,如何点击一个"复制"按钮,把一串文字复制到手机剪贴板,如上图所示. 看了网上的一些方法后,感觉那些方法都太复杂,有点要用插件,有 ...
- Ubuntu常用软件包管理命令
1.查看软件包xxx安装内容 #dpkg -L xxx 例子: #dpkg -L binutils //查看安装binutils包会安装哪些文件 2.列出系统已安装的或指定deb包的安 ...
- 关于通用的C#后台获取前台页面的标签的正则表达式
Regex reg = new Regex("<div[^>]*?class=\"类属性名称\"[^>]*>(.*?) </div> ...
- document事件及例子
一.关于鼠标事件:onclick:鼠标单击触发 ondbclick:鼠标双击触发 onmouseover:鼠标移上触发 onmouseout:鼠标离开触发 onmousemove:鼠标移动触发 二.关 ...
- ecshop调用指定分类和个数的文章列表
举例如首页调用方法: 1.先打开index.php文件找到以下代码: $smarty->assign('new_articles', index_get_new_articles()); // ...
- 关于MATLAB处理大数据坐标文件2017530
今天使用了所有特征并且用SVM测试数据 理由:SVM可以使用特征将测试集划分区域,比较单调.死板 结果:成绩很不理想,无疑又一次说明随机森林更适合大数据处理 第二次提交数据 用MATLAB运行11次运 ...
- Redis客户端管理工具,状态监控工具
TreeNMS是一款Redis web客户端管理工具,采用JAVA开发,实现基于web方式对Redis数据库进行管理.监控.数据维护. 功能包括:数据库的状态监控,库表的展示,key,value的展示 ...