传送门


值得注意的是一般的DAG的拓扑序列数量是NP问题,所以不能直接入手

题目中给出的图可以看做是一个树形图,虽然方向比较迷。考虑使用树形图的性质

不妨任选一个点为根做树形DP,注意到数的位置与方案数相关,所以也要设在状态内。故设\(f_{i,j}\)表示对于\(i\)及\(i\)的子树所有点构成的拓扑序列,\(i\)排在第\(j\)位的方案数,通过一个儿子一个儿子地合并来转移。

对于当前计算的点\(u\)的某一个儿子\(v\)已经算完,正要和\(u\)合并。设\(sz_u\)表示\(u\)和\(u\)的已合并子树的点数之和,并设\(u < v\),那么序列中\(v\)要在\(u\)的后面。

先枚举\(u\)在已合并序列中的位置\(j\),然后枚举\(v\)的子树对应的拓扑序列中有\(k\)个放在\(u\)的前面,不难得到转移方程:\(dp_{u,j+k} \leftarrow dp_{u,j} \times C_{j-1+k}^k \times C_{sz_u + sz_v - j - k} ^ {sz_v - k} \times \sum\limits_{i=k+1}^{sz_v} dp_{v,k}\)

如果\(u>v\)也是差不多的

前后缀和优化最后的\(\sum dp_{v,k}\)并预处理组合数

关于复杂度,注意到每一次合并的复杂度为"已合并的儿子大小"\(\times\)"当前合并的儿子大小",可以看作任意两个点只会在它们的LCA处产生\(1\)的复杂度,所以总复杂度是\(O(n^2)\)的。

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<ctime>
#include<cctype>
#include<algorithm>
#include<cstring>
#include<iomanip>
#include<queue>
#include<map>
#include<set>
#include<bitset>
#include<stack>
#include<vector>
#include<cmath>
#include<cassert>
//This code is written by Itst
using namespace std;inline int read(){int a = 0;char c = getchar();bool f = 0;while(!isdigit(c) && c != EOF){if(c == '-')f = 1;c = getchar();}if(c == EOF)exit(0);while(isdigit(c)){a = a * 10 + c - 48;c = getchar();}return f ? -a : a;
}const int MOD = 1e9 + 7;
int N , cntEd;
struct Edge{int end , upEd;
}Ed[2003];
int head[1007] , C[1007][1007] , dp[1007][1007] , sz[1007] , pre[1007][1007] , suf[1007][1007] , tmp[1007];inline void addEd(int a , int b){Ed[++cntEd].end = b;Ed[cntEd].upEd = head[a];head[a] = cntEd;
}inline char getc(){char c = getchar();while(c == ' ' || c == '\n' || c == '\r')c = getchar();return c;
}void init(){C[0][0] = 1;for(int i = 1 ; i <= 1000 ; ++i){C[i][0] = 1;for(int j = 1 ; j <= 1000 ; ++j)C[i][j] = (C[i - 1][j] + C[i - 1][j - 1]) % MOD;}
}void dfs(int u , int p){sz[u] = 1;dp[u][1] = 1;for(int i = head[u] ; i ; i = Ed[i].upEd)if(Ed[i].end != p){dfs(Ed[i].end , u);int v = Ed[i].end;sz[u] += sz[v];memset(tmp , 0 , sizeof(tmp));if(i & 1)for(int j = sz[u] - sz[v] ; j ; --j)for(int k = 0 ; k < sz[v] ; ++k)tmp[j + k] = (tmp[j + k] + 1ll * dp[u][j] * suf[v][k + 1] % MOD * C[j + k - 1][k] % MOD * C[sz[u] - j - k][sz[v] - k]) % MOD;elsefor(int j = sz[u] - sz[v] ; j ; --j)for(int k = 1 ; k <= sz[v] ; ++k)tmp[j + k] = (tmp[j + k] + 1ll * dp[u][j] * pre[v][k] % MOD * C[j + k - 1][k] % MOD * C[sz[u] - j - k][sz[v] - k]) % MOD;memcpy(dp[u] , tmp , sizeof(tmp));}for(int i = 1 ; i <= sz[u] ; ++i)pre[u][i] = (pre[u][i - 1] + dp[u][i]) % MOD;for(int i = sz[u] ; i ; --i)suf[u][i] = (suf[u][i + 1] + dp[u][i]) % MOD;
}int main(){
#ifndef ONLINE_JUDGEfreopen("in","r",stdin);//freopen("out","w",stdout);
#endifinit();for(int T = read() ; T ; --T){N = read();for(int i = 1 ; i < N ; ++i){int a = read() + 1;char c = getc();int b = read() + 1;if(c == '>')swap(a , b);addEd(a , b);addEd(b , a);}dfs(1 , 0);cout << pre[1][N] << endl;memset(dp , 0 , sizeof(dp));memset(pre , 0 , sizeof(pre));memset(suf , 0 , sizeof(suf));memset(head , 0 , sizeof(head));cntEd = 0;}return 0;
}
=

转载于:https://www.cnblogs.com/Itst/p/10406642.html

Luogu4099 HEOI2013 SAO 组合、树形DP相关推荐

  1. 【做题记录】 [HEOI2013]SAO

    P4099 [HEOI2013]SAO 类型:树形 \(\text{DP}\) 这里主要补充一下 \(O(n^3)\) 的 \(\text{DP}\) 优化的过程,基础转移方程推导可以参考其他巨佬的博 ...

  2. bzoj3167[HEOI2013]SAO

    这虽然是游戏,但可不是闹着玩的. --茅场晶彦 HEOI2013有一道SAO和一道ALO--SwordArtOnline和AlfheimOnline233333 一开始看到这道题,我觉得noip模拟赛 ...

  3. 容斥 + 树形dp ---- 2021 icpc 沈阳 L Perfect Matchings

    题目链接 题目大意: 就是给你一个2n2n2n个点的完全图,从这个图里面抽出2n−12n-12n−1条边,这些边形成一颗树,现在问你剩下的图里面点进行完美匹配有多少种方案? 解题思路: 一开始被完美匹 ...

  4. 2019 GDCPC or HDU6540 树形dp[计数dp] 详解

    题目链接 题目大意: 就是给你一颗nnn个点的树,树上有mmm个关键点,你可以选择若干个关键点组成集合SSS,这个集合满足任意两点在树上的距离不超过kkk,问你有多少种选法? 解题思路: 我们考虑树形 ...

  5. 【牛客每日一题】4.15 Treepath 题解(树上dfs/树形DP)

    题目链接:https://ac.nowcoder.com/acm/problem/14248 来源:牛客网 题目描述 给定一棵n个点的树,问其中有多少条长度为偶数的路径.路径的长度为经过的边的条数.x ...

  6. HDU - 4705 Y(树形dp)

    题目链接:点击查看 题目大意:给出一棵树,求三个点不在一条线上的个数 题目分析:正难取反,正着求不管是暴力还是有点技巧都是实现不了的,我们可以求出来三个点在一条直线上的方案数,然后用总的排列组合的方案 ...

  7. Chino with Triangle ( 西工大程序设计创新实践基地春季选拔赛)树形dp

    https://ac.nowcoder.com/acm/contest/553/E 题意,是中文,没有什么读不懂的. 做法,肯定是树形dp,如果想到,正难则反,一条链上的不可以组成三角形,这道题就不难 ...

  8. uva 10859 放置街灯树形dp

    首先,本题的优化目标有两个:放置的街灯a应该尽量少:被两灯同时照亮的边数b应该尽量大.为了统一起见,我们把后者替换为:恰好被一盏灯照亮的边数c应该尽量小,然后改用x = Ma+c作为优化目标,其中一个 ...

  9. 树形DP总结,持续更新

    自己做了动态规划的题目已经有了一个月,但是成效甚微,所以来总结一下动态规划,希望自己能够温故知新.这个博客是关于树形dp的,动态规划的一类题目. 首先从最简单的树形DP入手,树形DP顾名思义就是一棵树 ...

最新文章

  1. 面试最后HR都要问一句有没有什么问题要问我?
  2. Python读取Json字典写入Excel表格的方法
  3. java集合框架总结之思维导图
  4. 超级计算机清华,从清华到华科 名校为何主办超级计算机大赛?
  5. Mysql数据库使用及其问题合集一
  6. iOS获取最顶层ViewController
  7. Amazon发布可持续性数据集,可用于多个领域的数据分析
  8. eclipse远程连接hadoop_Hadoop群启集群
  9. 剑指offer——3.实现数组中重复数字查找
  10. Java多线程编程(2)--多线程编程中的挑战
  11. php接收url的json,api-php中url接收的json数据,json_decode为空
  12. git diff与git status
  13. 学画画怎么画三点透视图
  14. word转pdf转换器11.0注册码
  15. 未雨绸缪:面试前为何要带一份不一定被阅的简历?
  16. LeetCode:917. 仅仅反转字母————简单
  17. POI 图表中加入文本框
  18. vue-cli生成的spa项目js、css、fonts、images文件路径找不到
  19. 相机标定的理解及采用opencv和matlab工具箱的标定方法
  20. MySQL 查询表中重复数据

热门文章

  1. [转载]常用正则表达式
  2. InnoDB存储引擎对MVCC的实现
  3. 硅谷大佬为何加速逃离加州:赋税过重,生活质量持续恶化
  4. Fedora14 yum 安装源的地址配置到官方归档地址
  5. 危机时保路人还是保乘客?无人车伦理困境背后:谁来制定算法规则
  6. php api 无符号整数基数为16的整数参数的字符串表示形式,php基础语法
  7. mysql master-slave_mysql 同步 master-slave
  8. java对docker_Java和Docker限制问题
  9. typora将html转为格式,Typora 修改配置文件实现自定义标签样式(常用)
  10. 原码一位乘法器设计_对原码、反码和补码的加深理解