[HEOI2013]SAO(树上dp,计数)
[HEOI2013]SAO
(这写了一个晚上QAQ,可能是我太蠢了吧.)
题目说只有\(n-1\)条边,然而每个点又相互联系.说明它的结构是一个类似树的结构,但是是有向边连接的,题目问的是方案个数,那么首先想到的肯定是树上dp.
但是这题有向边,从一个点出发,不一定可以遍历整棵树.那么肯定要对每条边建反边,打个标记分类讨论.
解决了建模的问题,接下来就是怎么dp了.
容易发现这个其实就是求这个"类树形图"的拓扑排序方案数,然而我们知道拓扑排序的方案计数是个NP问题,用状压解决,这题有"类树"这个优良特性.所以我们要另辟蹊径.
我们设状态的时候要保证这个状态尽量可以描述这个状态的特点,从而协助我们转移.考虑状态\(dp[u][i]\)表示u和它的子树的点组成的满足拓扑关系的排列的中u点在第i位上.这样以来,我们就根据这个状态知道了,u的位置,知道了u之前有多少个点,知道u之后有多少个点,我们还可以通过它和它子树的节点数推断要在一些范围插入一些点,是不是很棒~
考虑怎么转移呢?
首先是边界条件,一个点(没有子树)单独站在第一位的方案数是1.
再就是考虑合并子树信息.先讨论u优先于v的情况.
最开始,只有1个点,此时加入第一棵子树,这个时候\(dp[u][i]\)描述的状态到处都是空位,出了u站在i位置,其他的都随便这棵子树里的点乱站.我们考虑从\(dp[v][j]\)转移而来,于是就是u和v的位置固定了,其他的可以随意填充,其他的点有多少个呢?\(sz[v]\)吗?
等等好像还有一些限制! u要先于v! 那么v在合并后的排名必须在u之后,那么v在之前子树的排名最低最低也是\(k-i+1\)名,这样v就刚好在u后面一位.那么其他的\(k-1\)个点就随意分布u之前的\(i-1\)个空位之间,剩余的\(sz[u]-k\)个点在\(u\)之后的\(sz[u]-sz[v]-k\)个空位里,那么状态转移方程就是:
\]
如果是v先于u再像上面那样分析就可以了.
#include<bits/stdc++.h>
#define maxn 1005
#define mod 1000000007
#define ll long long
using namespace std;
int cnt,n,T,ans,sum[maxn][maxn];
//dp[u][i]表示u节点和它的子树,组成的拓扑排列中,u的拓扑序
int c[maxn][maxn],dp[maxn][maxn],sz[maxn],vis[maxn];
int head[maxn],nxt[maxn<<1],w[maxn<<1],to[maxn<<1];
int C(int n,int m){if(n<0||m<0||n<m)return 0;return c[n][m];}
void qm(int &x,int y){x+=y;if(x>=mod)x-=mod;}
void add(int u,int v,int ww)
{
nxt[++cnt]=head[u];head[u]=cnt;
to[cnt]=v;w[cnt]=ww;
}
void init()
{
for(int i=0;i<=1000;i++)c[i][0]=1;
for(int i=1;i<=1000;i++)
for(int j=1;j<=i;j++)c[i][j]=(c[i-1][j-1]+c[i-1][j])%mod;
}
void clear()
{
memset(dp,0,sizeof(dp));memset(sz,0,sizeof(sz));
memset(vis,0,sizeof(vis));memset(sum,0,sizeof(sum));
memset(head,0,sizeof(head));cnt=0;
}
void dfs(int u)
{
vis[u]=1;sz[u]=1;dp[u][1]=1;
for(int ii=head[u];ii;ii=nxt[ii])
{
int v=to[ii];if(vis[v])continue;
dfs(v);sz[u]+=sz[v];
if(w[ii])//u优先于v
{
for(int i=sz[u],s=0;i>=1;i--,dp[u][i+1]=s,s=0)//填表法合并子树信息,枚举u的拓扑序
for(int k=1;k<=min(sz[u]-sz[v],i);k++)//枚举u和其它已经合并到u上的子树的状态
{
if(sz[v]<=i-k)continue;
int tt=(sum[v][sz[v]]-sum[v][i-k]+mod)%mod;
qm(s,(ll)dp[u][k]*tt%mod*C(i-1,k-1)%mod
*C(sz[u]-i,sz[u]-sz[v]-k)%mod);
/*
暴力转移:
for(int j=i-k+1;j<=sz[v];j++)
qm(sum,(ll)dp[u][k]*dp[v][j]%mod
*C(i-1,k-1)%mod*C(sz[u]-i,sz[u]-sz[v]-k)%mod);
*/
}
}
else//v优先于u
{
for(int i=sz[u],s=0;i>=1;i--,dp[u][i+1]=s,s=0)
for(int k=1;k<=min(sz[u]-sz[v],i-1);k++)
{
int tt=sum[v][min(sz[v],i-k)];
qm(s,(ll)dp[u][k]*tt%mod*C(i-1,k-1)%mod
*C(sz[u]-i,sz[u]-sz[v]-k)%mod);
}
}
}
for(int i=1;i<=sz[u];i++)//前缀和优化
sum[u][i]=(sum[u][i-1]+dp[u][i])%mod;
}
int main()
{
init();cin>>T;
while(T--)
{
char ty;clear();cin>>n;
for(int i=1,u,v;i<n;i++)//u优先v,连1边
cin>>u>>ty>>v,v++,u++,add(u,v,ty=='<'),add(v,u,ty=='>');
dfs(1);ans=0;
for(int i=1;i<=n;i++)ans+=dp[1][i],ans%=mod;
printf("%d\n",ans);
}
return 0;
}
[HEOI2013]SAO(树上dp,计数)的更多相关文章
- 3167: [Heoi2013]Sao [树形DP]
3167: [Heoi2013]Sao 题意: n个点的"有向"树,求拓扑排序方案数 Welcome to Sword Art Online!!! 一开始想错了...没有考虑一个点 ...
- [BZOJ3167][P4099][HEOI2013]SAO(树形DP)
题目描述 Welcome to SAO ( Strange and Abnormal Online).这是一个 VR MMORPG, 含有 n 个关卡.但是,挑战不同关卡的顺序是一个很大的问题. 有 ...
- BZOJ 3167 [Heoi2013]Sao ——树形DP
BZOJ4824的强化版. 改变枚举的方案,使用前缀和进行DP优化. 然后复杂度就是$O(n^2)$了. #include <map> #include <cmath> #in ...
- [BZOJ3167][HEOI2013]SAO[树dp+组合数学]
题意 给定 \(n\) 个节点和 \(n-1\) 个限制,每个节点有一个权值,每个限制形如:\(a_i< a_j\) ,问有多少个 \(1\) 到 \(n\) 排列满足要求. \(n\leq 1 ...
- 洛谷 4099 [HEOI2013]SAO——树形DP
题目:https://www.luogu.org/problemnew/show/P4099 结果还是看了题解才会…… 关键是状态,f[ i ][ j ] 表示 i 子树. i 号点是第 j 个出现的 ...
- P4099 [HEOI2013]SAO(树形dp)
P4099 [HEOI2013]SAO 我们设$f[u][k]$表示以拓扑序编号为$k$的点$u$,以$u$为根的子树中的元素所组成的序列方案数 蓝后我们在找一个以$v$为根的子树. 我们的任务就是在 ...
- 【BZOJ3167】[HEOI2013]SAO(动态规划)
[BZOJ3167][HEOI2013]SAO(动态规划) 题面 BZOJ 洛谷 题解 显然限制条件是一个\(DAG\)(不考虑边的方向的话就是一棵树了). 那么考虑树型\(dp\),设\(f[i][ ...
- P4099 [HEOI2013]SAO
P4099 [HEOI2013]SAO 贼板子有意思的一个题---我()竟然没看题解 有一张连成树的有向图,球拓扑序数量. 树形dp,设\(f[i][j]\)表示\(i\)在子树中\(i\)拓扑序上排 ...
- BZOJ 3167: [Heoi2013]Sao
3167: [Heoi2013]Sao Time Limit: 30 Sec Memory Limit: 256 MBSubmit: 96 Solved: 36[Submit][Status][D ...
随机推荐
- 解决jenkins 发送邮件图片乱码问题
1.在本地mac上测试邮件发送正常 发送邮件内容图片没有乱码 2.公司测试服务器是一台windows2008的系统jmeter + ant jenkins 安装完成后 设置邮件发送格式模板,设置附件 ...
- 个人永久性免费-Excel催化剂功能第49波-标准数据结构表转报表样式结果
中国的企业信息化,已经过去了20年,企业里也产生了大量的数据,IT技术的信息化管理辅助企业经营管理也已经得到广泛地认同,现在就连一个小卖部都可以有收银系统这样的信息化管理介入.但同时也有一个很现实的问 ...
- ACM线性基学习笔记
https://www.cnblogs.com/31415926535x/p/11260897.html 概述 最近的几场多校出现了好几次线性基的题目,,会想起之前在尝试西安区域赛的一道区间异或和最大 ...
- web设计_9_CSS常用布局,响应式
一个完整的页面和其中的组件该如何具备灵活性. 怎么样利用CSS来实现无论屏幕.窗口以及字体的大小如何变化,都可以自由扩展和收缩的分栏式页面. 要决定使用流动布局.弹性布局还是固定宽度的布局,得由项目的 ...
- jmeter Linux环境执行总报错 cannot allocate memory
1.windows环境写好的测试用例,执行没有问题,在Linux环境跑总是报错,提示如下 cannot allocate memory 2.一开始以为是哪块设置有问题,因为脚本里边有设置邮件自动发送, ...
- Angular JS 中的服务注册方法
在Angular JS中创建服务的几种方法 factory() service() constant() value() provider() factory(name,fn(){}) 该服务为单例的 ...
- superset安装文档
1 安装python3.6 yum install epel-release -y yum install https://centos7.iuscommunity.org/ius-release.r ...
- Linux 常见的常识及常用快捷键方式
1. ,请写出linux系统中常见一级目录的名称及作用. /root : 超级用户的家目录 /home: 普通用户的家目录 /boot: 启动目录,启动相关文件(系统内核启动文件) /de ...
- java 8中新的日期和时间API
java 8中新的日期和时间API 使用LocalDate和LocalTime LocalDate的实例是一个不可变对象,它只提供了简单的日期,并不含当天的时间信息.另外,它也不附带任何与时区相关的信 ...
- lvs模式及算法
一.三种模式 (一).Virtual Servervia Network Address Translation(VS/NAT) 通过网路地址转换,调度器重写请求报文的目标地址,根据预设的调度算法,将 ...