51NOD 1806 wangyurzee的树(容斥原理 + 组合数学)
来源:互联网 发布:组策略隐藏网络配置 编辑:程序博客网 时间:2024/05/22 02:18
传送门
wangyurzee有n个各不相同的节点,编号从1到n。wangyurzee想在它们之间连n-1条边,从而使它们成为一棵树。
可是wangyurzee发现方案数太多了,于是他又给出了m个限制条件,其中第i个限制条件限制了编号为u[i]的节点的度数不能为d[i]。
一个节点的度数,就是指和该节点相关联的边的条数。
这样一来,方案数就减少了,问题也就变得容易了,现在请你告诉wangyurzee连边的方案总数为多少。
答案请对1000000007取模。
样例解释
总方案共有3种,分别为{(1,2),(1,3)},{(1,2),(2,3)},{(2,3),(1,3)}。其中第二种方案节点1的度数为2,不符合要求,因此答案为2。
Input
第一行输入2个整数n(1<=n<=1000000),m(0<=m<=17)分别表示节点个数以及限制个数。
第2行到第m+1行描述m个限制条件,第i+1行为2个整数u[i],d[i],表示编号为u[i]的节点度数不能为d[i]。
为了方便起见,保证1<=ui<=m。同时保证1<=ui<=n,1<=di<=n-1,保证不会有两条完全相同的限制。
Output
输出一行一个整数表示答案。
Input示例
3 1
1 2
Output示例
2
解题思路:
首先需要知道一个 prufer序列,具体详见prufer数列学习笔记
因为只要一个purfer序列确定了,那么由这个序列所组成的无根树也就确定了,所以只用算purfer序列的方案就可以了。
我们还需要知道的一个知识点就是:
这里解释一下:底数是指
然后我们发现题目中给出的限制条件很少
那么我们假设选取了
因为一个
那么我们现在先求出
然后
现在就对 prufer 序列中已知的条件进行排列
现在对
现在还剩
然后现在对
…
直到这选定
现在还剩余
将所有的乘起来之后就是如下公式:
然后相应的进行容斥,将最开始的总方案数算出来,然后奇减偶加。
trick:这里有几个坑
1): 当只有一个点的时候,如果 m=1 直接输出 0,否则都是 1
2):有一种情况是一个点可能有多种限制情况,这样的需要考虑:
比如 :
n = 4 m = 2
1 1
1 2
代码:
#include <iostream>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <algorithm>#include <math.h>using namespace std;typedef long long LL;const LL MOD = 1e9+7;const int MAXN = 20;int u[MAXN], v[MAXN], vis[MAXN];LL Pow(LL a, LL b){ LL ans = 1; while(b){ if(b & 1) ans = ans * a % MOD; b>>=1; a = a * a % MOD; } return ans;}LL fac[1000005], Inv[1000005];void Init(){ fac[0] = fac[1] = Inv[0] = Inv[1] = 1; for(int i=2; i<1000005; i++) fac[i] = fac[i-1] * i % MOD; for(int i=2; i<1000005; i++) Inv[i] = (MOD - MOD / i) * Inv[MOD % i] % MOD; for(int i=2; i<1000005; i++) Inv[i] = Inv[i-1] * Inv[i] % MOD;}int main(){ Init(); int n, m; scanf("%d%d", &n, &m); if(n == 1){ if(m == 1) {puts("0"); return 0;} else {puts("1"); return 0;} } for(int i=0; i<m; i++) scanf("%d%d", &u[i], &v[i]); LL ans = Pow(n, n-2); int state = (1<<m); int aa = 0; for(int i=1; i<state; i++){ int cnt = 0, sum = 0; memset(vis, 0, sizeof(vis)); LL t = 1; for(int j=0; j<m; j++){ if(i & (1<<j)){ if(vis[u[j]]) goto A; cnt++; sum += (v[j]-1); vis[u[j]] = 1; t = t * Inv[v[j]-1] % MOD; } } if(sum > n-2) { A:; continue; } LL tmp = fac[n-2] * Inv[n-2-sum] % MOD; tmp = tmp * Pow(n-cnt, n-2-sum) % MOD; tmp = tmp * t % MOD; if(cnt & 1) ans = (ans - tmp) % MOD; else ans = (ans + tmp) % MOD; } ans = (ans % MOD + MOD) % MOD; printf("%lld\n",ans); return 0;}
- 51NOD 1806 wangyurzee的树(容斥原理 + 组合数学)
- 51nod 1806 wangyurzee的树(purfer,容斥原理)
- 51nod 1806 wangyurzee的树[purfer][容斥]
- 51nod 1806 wangyurzee的树
- 51Nod-1806-wangyurzee的树
- 51nod 1806 wangyurzee的树
- 【51Nod 1806】wangyurzee
- [容斥+Purfer编码] 51Nod1806 wangyurzee的树
- 51nod 序列变换 [容斥原理+莫比乌斯函数]【数论+组合数学】
- 51 nod 1486 大大走格子 容斥原理+组合数学+dp
- [容斥原理+组合数学]51 Nod 1829——函数
- 容斥原理(组合数学)总结
- 51nod 1486 大大走格子(组合数学+容斥)
- 51nod 1317 相似字符串对 容斥原理+数学
- 51nod 1806 wangyurzee的树(prufer编码求生成树的个数)
- [组合数学]容斥原理的初步总结
- 51nod 1251 Fox序列的数量 容斥原理+数学
- UVa 11806 - Cheerleaders (组合数学 容斥原理)
- protobuf入门教程(四):repeated限定修饰符
- 数据类型及数据结构资料
- weblogic被root重启后出现 java.lang.ClassCastException
- vue2.0之axios使用详解(一)
- Nginx增加自定义域名配置服务
- 51NOD 1806 wangyurzee的树(容斥原理 + 组合数学)
- Array() 对象
- 生产者消费者模型
- Windows下使用Hexo+GithubPage搭建博客
- CSDN
- C# 线程中打开新窗体
- 高通常用缩写
- python3爬取淘宝信息
- 用java程序登录应用程序,自动化测试