[HEOI 2013]SAO
Description
给你一个 \(n\) 个节点的有向树,问你这棵树的拓扑序个数,对大质数取模。多测,测试组数 \(T\)。
\(1\leq n\leq 1000, 1\leq T\leq 5\)
Solution
以 1 为根。记 \(f_{u,i}\) 表示 \(u\) 为根的子树中 \(u\) 的拓扑序号为 \(i\) 时的方案数。
从儿子 \(v\) 向父亲 \(u\) 转移时,考虑 \((u,v)\) 的方向。以 \(u\rightarrow v\) 为例。
枚举 \(u\) 的拓扑序号 \(i\),\(v\) 的拓扑序 \(j\)。那么 \(u,v\) 的分别的原排列如图示(\(A,B\) 为原先在 \(u\) 前/后的部分,\(C,D\) 同理),
\[
\begin{aligned}
\underline{\quad A\quad}&\quad i\quad\underline{\quad B\quad}\\
&\ \ \ \downarrow\\
\underline{\quad C\quad}&\quad j\quad\underline{\quad D\quad}
\end{aligned}
\]
我们考虑 \(u\) 在新序列中的位置 \(k\),可以得到
\[
\text{new}f_{u,k} = \sum_{i,j}{k-1\choose i-1}{sz_u+sz_v-k\choose sz_u-i}f_{u,i}f_{v,j}
\]
其中 \(sz_u\) 表示子树 \(u\) 的大小。
容易发现 \(j\) 这一维可以前缀和优化。
故最终复杂度为 \(O(n^2)\)。
Code
#include <bits/stdc++.h>
using namespace std;
const int yzh = 1000000007, N = 1000+5;
int f[N][N], sz[N], t, n, u, v, g[N], fac[N], ifac[N];
struct tt {
int to, nxt, c;//0->
} edge[N<<1];
int path[N], top;
char sign;
int C(int n, int m) {return 1ll*fac[n]*ifac[m]%yzh*ifac[n-m]%yzh; }
void dfs(int u, int fa) {
f[u][1] = sz[u] = 1;
for (int v, i = path[u]; i; i = edge[i].nxt)
if ((v = edge[i].to) != fa) {
dfs(v, u);
memcpy(g, f[u], sizeof(g));
memset(f[u], 0, sizeof(g));
if (edge[i].c == 0) {
for (int i = 1; i <= sz[u]; i++)
for (int k = i; k <= i+sz[v]-1; k++)
(f[u][k] += 1ll*C(k-1, i-1)*C(sz[u]+sz[v]-k, sz[u]-i)%yzh*g[i]%yzh*(f[v][sz[v]]-f[v][k-i])%yzh) %= yzh;
} else {
for (int i = 1; i <= sz[u]; i++)
for (int k = i+1; k <= i+sz[v]; k++)
(f[u][k] += 1ll*C(k-1, i-1)*C(sz[u]+sz[v]-k, sz[u]-i)%yzh*g[i]%yzh*f[v][k-i]%yzh) %= yzh;
}
sz[u] += sz[v];
}
for (int i = 1; i <= n; i++) (f[u][i] += f[u][i-1]) %= yzh;
}
void add(int u, int v, int c) {
edge[++top] = (tt){v, path[u], c};
path[u] = top;
}
int main() {
n = 1000;
ifac[0] = ifac[1] = fac[0] = 1;
for (int i = 2; i <= n; i++) ifac[i] = -1ll*yzh/i*ifac[yzh%i]%yzh;
for (int i = 1; i <= n; i++)
ifac[i] = 1ll*ifac[i]*ifac[i-1]%yzh,
fac[i] = 1ll*i*fac[i-1]%yzh;
scanf("%d", &t);
while (t--) {
scanf("%d", &n); top = 0;
for (int i = 1; i <= n; i++) {
path[i] = sz[i] = 0;
for (int j = 1; j <= n; j++) f[i][j] = 0;
}
for (int i = 1; i < n; i++) {
scanf("%d %c %d", &u, &sign, &v); ++u, ++v;
if (sign == '<') add(u, v, 0), add(v, u, 1);
else add(u, v, 1), add(v, u, 0);
}
dfs(1, 0);
printf("%d\n", (f[1][n]+yzh)%yzh);
}
return 0;
}
[HEOI 2013]SAO的更多相关文章
- [BZOJ 3167][HEOI 2013]SAO
[BZOJ 3167][HEOI 2013]SAO 题意 对一个长度为 \(n\) 的排列作出 \(n-1\) 种限制, 每种限制形如 "\(x\) 在 \(y\) 之前" 或 & ...
- 解题:HEOI 2013 SAO
题面 不好讲,直接上式子吧=.= 设$dp[i][j]$表示考虑完$i$的子树后$i$的排名为$j$的方案数,然后转移类似树形背包,具体来说是(这里假设子树在$i$后选,其实反过来还用这个式子答案也是 ...
- [HEOI 2013 day2] SAO (树形动态规划)
题目大意 给一棵N个节点的有向树(N <= 1000),求其拓扑序列个数. 思路 我们将任意一个点作为根,用dp[i][j]表示以节点i为根的子树满足节点i在第j个位置上的拓扑序列的个数.在求节 ...
- 【BZOJ 3165】【HEOI 2013】Segment
往区间上覆盖一次函数,做法是用线段树维护标记永久化. 每次都忘了线段树要4倍空间,第一次交总是RE,再这么手残的话考场上就真的要犯逗了. #include<cstdio> #include ...
- [HEOI 2013 day2] 钙铁锌硒维生素 (线性代数,二分图匹配)
题目大意 给定两个n阶方阵,方阵B的行i能匹配方阵A的行j当且仅当在第一个方阵中用行向量i替换行向量j后,第一个方阵满秩,显然这是个二分图匹配问题,问是否存在完美匹配,如果存在,还要输出字典序最小的方 ...
- 【BZOJ 3166】【HEOI 2013】Alo
http://www.lydsy.com/JudgeOnline/problem.php?id=3166 这道题难点在于求能对一个次大值有贡献的区间. 设这个次大值为\(a_i\),\(a_i\)左边 ...
- [总结]一些 DP 优化方法
目录 注意本文未完结 写在前面 矩阵快速幂优化 前缀和优化 two-pointer 优化 决策单调性对一类 1D/1D DP 的优化 \(w(i,j)\) 只含 \(i\) 和 \(j\) 的项--单 ...
- 2013 Asia Changsha Regional Contest---Josephina and RPG(DP)
题目链接 http://acm.hdu.edu.cn/showproblem.php?pid=4800 Problem Description A role-playing game (RPG and ...
- SharePoint 2013: A feature with ID has already been installed in this farm
使用Visual Studio 2013创建一个可视web 部件,当右击项目选择"部署"时报错: "Error occurred in deployment step ' ...
随机推荐
- 红帽RHCE培训-课程2笔记目录
目录 1 kickstart自动安装 DHCP+TFTP(syslinux) +FTP +KICKSTART ~/anaconda-ks.cfg system-config-kickstart 2 g ...
- iOS-image图片旋转方向
https://blog.csdn.net/qq_36557133/article/details/85760469 最近在做项目的时候发现资源包内的图片的方向不对,但也不想让UI切一个新图,所以需要 ...
- 【代码学习】PYTHON迭代器
一.迭代器 迭代是访问集合元素的一种方式.迭代器是一个可以记住遍历的位置的对象.迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束.迭代器只能往前不会后退. 二.可迭代对象 以直接作用于 ...
- 201771010135 杨蓉庆/张燕《面对对象程序设计(java)》第十三周学习总结
1.实验目的与要求 (1) 掌握事件处理的基本原理,理解其用途: (2) 掌握AWT事件模型的工作机制: (3) 掌握事件处理的基本编程模型: (4) 了解GUI界面组件观感设置方法: (5) 掌握W ...
- [代码记录] C语言链表
#开始 · 简单的创建链表 #代码 #include<conio.h> #include<stdio.h> #include<stdlib.h> struct St ...
- 吴裕雄 python 神经网络——TensorFlow 三层简单神经网络的前向传播算法
import tensorflow as tf w1= tf.Variable(tf.random_normal([2, 3], stddev=1, seed=1)) w2= tf.Variable( ...
- ubuntu安装与设置
为学习Linux,在虚拟机中安装类ubuntu18.04,刚装完系统时间是不对的,系统中也没有gcc,g++. 关于安装软件无非就是: sudo apt-get install gcc sudo ap ...
- Shiro入门学习与实战(一)
一.概述 1.Shiro是什么? Apache Shiro是java 的一个安全框架,主要提供:认证.授权.加密.会话管理.与Web集成.缓存等功能,其不依赖于Spring即可使用: Spring S ...
- Ubuntu系统中创建虚拟环境
1.虚拟环境产生的原因:如果在一台电脑上, 想开发多个不同的项目, 需要用到同一个包的不同版本, 如果使用上面的命令, 在同一个目录下安装或者更新, 新版本会覆盖以前的版本, 其它的项目就无法运行了. ...
- twisted reactor 实现源码解析
twisted reactor 实现源码解析 1. reactor源码解析 1.1. 案例分析代码: from twisted.internet import protocol fro ...