看这道题目懵逼了好久, \(m <= 17\) 一眼容斥,然而并没有想到怎么求出生成树的个数。然后灵光一闪——我不是学过一个叫Prüfer编码的东西嘛?!那就完美解决啦~

  Prüfer编码就是将一棵无根树映射到一串编码上的编码方法,一棵 \(n\) 个节点的树与一个长度为 \(n - 2\) 的编码串一一对应。所以我们要求合法的 = 总数 \(n ^ {n - 2}\) - 不合法的方案数。不合法的方案数 = 至少有 \(1\) 个不合法 - 至少有 \(2\) 个不合法 + 至少有\(3\) 个不合法……有何求出至少有 \(k\) 个不合法的方案数呢?

  我们可以首先搜索出这 \(k\) 个限制(复杂度约为 \(2^{17}\)),然后令这\(k\) 个限制的 \(sum = \sum d[i] - 1\),\(sum\) 即为这 \(k\) 个限制中所牵涉到的节点在数列中一共应该出现的次数。满足这个限制(每一个节点出现 \(d[i] - 1\) 次)的数列个数即为 \(\frac{sum!}{\prod (d[i] - 1)!}\)。又因为这 \(sum\) 个数可以出现在长度为 \(n - 2\) 的数列中的任何位置,所以 乘上\(C(n - 2, sum)\),剩下的 \(n - 2 - sum\) 个数则可以随便选择,有 \((n - k) ^ {n - sum - 2}\) 种方案。完美~

#include <bits/stdc++.h>
using namespace std;
#define maxn 2000000
#define int long long
#define mod 1000000007
int n, m, fac[maxn];
int cnt, tot = , Ans = , S[maxn];
bool mark[maxn], vis[maxn]; int read()
{
int x = , k = ;
char c;
c = getchar();
while(c < '' || c > '') { if(c == '-') k = -; c = getchar(); }
while(c >= '' && c <= '') x = x * + c - '', c = getchar();
return x * k;
} struct node
{
int x, d;
}Q[maxn]; int Qpow(int x, int timer)
{
int base = ;
for(; timer; timer >>= , x = x * x % mod)
if(timer & ) base = base * x % mod;
return base;
} int C(int n, int m)
{
if(m > n) return ;
return fac[n] * Qpow(fac[m], mod - ) % mod * Qpow(fac[n - m], mod - ) % mod;
} void Search(int now, int last)
{
if(m - last + < now) return;
if(!now)
{
int tem = , sum = ;
for(int i = ; i <= cnt; i ++)
tem = tem * (fac[Q[S[i]].d - ]) % mod,
sum += Q[S[i]].d - ;
if(sum > n - ) return;
tem = Qpow(tem, mod - );
tem = tem * fac[sum] % mod * C(n - , sum) % mod * Qpow(n - cnt, n - sum - ) % mod;
if(cnt & ) Ans = (Ans - tem + mod) % mod;
else Ans = (Ans + tem) % mod;
return;
}
for(int i = last; i <= m; i ++)
{
if(vis[Q[i].x]) continue;
S[++ cnt] = i, vis[Q[i].x] = ; Search(now - , i + );
cnt --, vis[Q[i].x] = ;
}
} signed main()
{
n = read(), m = read();
for(int i = ; i <= m; i ++)
Q[i].x = read(), Q[i].d = read();
if(n - > ) Ans = Qpow(n, n - );
else
{
printf("1\n");
return ;
}
fac[] = ;
for(int i = ; i <= n; i ++) fac[i] = fac[i - ] * i % mod;
for(int i = ; i <= m; i ++) Search(i, );
printf("%lld\n", Ans);
return ;
}

【题解】51nod 1806 wangyurzee的树的更多相关文章

  1. 51nod 1806 wangyurzee的树

    基准时间限制:1 秒 空间限制:131072 KB    wangyurzee有n个各不相同的节点,编号从1到n.wangyurzee想在它们之间连n-1条边,从而使它们成为一棵树.可是wangyur ...

  2. 题解 P1276 校门外的树(增强版)

    前言 本蒟蒻重学线段树,发现了这道题可以用线段树做. 虽然数据范围很小可以直接暴力,但由于在练习线段树所以打算用线段树写这道题. 本题解针对已经有线段树基础的巨佬,不懂线段树原理的话可以学习线段树后再 ...

  3. 51nod 1443 路径和树(最短路)

    题目链接:https://www.51nod.com/onlineJudge/questionCode.html#!problemId=1443 1443 路径和树 题目来源: CodeForces ...

  4. 51nod 1443 路径和树(最短路树)

    题目链接:路径和树 题意:给定无向带权连通图,求从u开始边权和最小的最短路树,输出最小边权和. 题解:构造出最短路树,把存留下来的边权全部加起来.(跑dijkstra的时候松弛加上$ < $变成 ...

  5. 51nod 1681 公共祖先 | 树状数组

    51nod 1681 公共祖先 有一个庞大的家族,共n人.已知这n个人的祖辈关系正好形成树形结构(即父亲向儿子连边). 在另一个未知的平行宇宙,这n人的祖辈关系仍然是树形结构,但他们相互之间的关系却完 ...

  6. 51Nod 1737 配对(树的重心)

    http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1737 题意: 思路: 树的重心. 树的重心就是其所以子树的最大的子树结点 ...

  7. 51nod 1272 思维/线段树

    http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1272 1272 最大距离 题目来源: Codility 基准时间限制:1 ...

  8. HH的项链题解(离线思想+链表+树状数组)

    本人第一篇博客重磅推出!!! 希望各位朋友以后多多捧场也多给写意见(我个人喜欢把题解写得啰嗦一点,因为这样方便理解,各位巨佬勿喷) 来讲一道提高+/省选-的骚题:HH的项链(这个HH你理解成皇后呵呵哈 ...

  9. 51nod 1376【线段树维护区间最大值】

    引自:wonter巨巨的博客 定义 dp[i] := 以数字 i(不是下标 i)为结尾的最长上升长度 然后用线段树维护 dp[i]: 每个节点维护 2 个信息,一个是当前区间的最大上升长度,一个是最大 ...

随机推荐

  1. 一个例子说明substr(), mb_substr() 和 mb_strcut()之间的区别

    例子来自PHP官方文档,我只是翻译下. http://www.php.net/manual/zh/function.mb-strcut.php header( 'Content-Type:text/h ...

  2. Redis系列七 主从复制(Master/Slave)

    主从复制(Master/Slave) 1.是什么 也就是我们所说的主从复制,主机数据更新后根据配置和策略,自动同步到备机的master/slaver机制,Master以写为主,Slave以读为主. 2 ...

  3. android学习十 ActionBar

    1.api level大于等于11 支持,或者使用兼容库,但兼容库的问题很多. 2.一个操作栏属于一个活动,并具有其生命周期 3.操作栏分3类:a.选项卡操作栏,b.列表操作栏,c.标准操作栏 4.获 ...

  4. Git笔记——01

    Git - 幕布 Git   教程:https://www.liaoxuefeng.com/wiki/0013739516305929606dd18361248578c67b8067c8c017b00 ...

  5. Selenium(Python)驱动Chrome浏览器

    Chrome浏览器与chromedriver.exe驱动可以是官网上最新的, 随意! Chrome.py: from selenium import webdriverfrom selenium.we ...

  6. 389. Valid Sudoku【LintCode java】

    Description Determine whether a Sudoku is valid. The Sudoku board could be partially filled, where e ...

  7. JavaScript 字符串 & Math & Date

    字符串 字符串就是零个或多个排在一起的字符,放在单引号或双引号之中. 'abc' "abc" 单引号字符串的内部,可以使用双引号.双引号字符串的内部,可以使用单引号. 'key=& ...

  8. JavaScript 之 对象/JSON/数组

    对象 简单说,所谓对象,就是一种无序的数据集合,由若干个“键值对”(key-value)构成. var obj = { p: 'Hello World' }; 上面代码中,大括号就定义了一个对象,它被 ...

  9. Java进阶知识点:并发容器背后的设计理念

    一.背景 容器是Java编程中使用频率很高的组件,但Java默认提供的基本容器(ArrayList,HashMap等)均不是线程安全的.当容器和多线程并发编程相遇时,程序员又该何去何从呢? 通常有两种 ...

  10. 《Linux编程大作业》

    一.要求 作业题目 Linux下的多进程/线程网络通信 作业目标 要求学生熟练掌握<Linux编程>课程中的知识点,包括Linux常用命令.bash脚本.编译和调试环境.读写文件.进程间通 ...