[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 ...
随机推荐
- ElasticSearch7.2安装
1.环境 Java -version:java11 centos: 7.2 elasticsearch: 7.2 2.获取压缩包 wget https://artifacts.elastic.co/d ...
- Kafka部署
Kafka依赖Zookeeper,虽然Kafka自带zookeeper,但是建议单独部署,所以先部署Zookeeper. 测试环境 citus1,citus2,citus3三台机器.对主机名和ip在/ ...
- Spark on YARN资源申请
1.spark submit参数 $ ./bin/spark-submit --class path.to.your.Class --master yarn --deploy-mode cluster ...
- [记录]FIO测试磁盘iops性能
FIO测试磁盘iops性能 1.SATA和SAS盘原生IOPS如下: 2.RAID磁盘阵列对应的写惩罚级别: 3.计算功能性IOPS公式如下: 功能性 IOPS=(((总原生 IOPS×写 %))/( ...
- [sublime3] 在linux下的终端中使用sublime3打开文件
通过ln命令创建软连接实现 echo $PATH 查看路径 例 我的路径是: /home/rh/anaconda3/bin:/home/rh/bin:/home/rh/.local/bin:/usr/ ...
- Linux 安装MySql——ubuntu版
这里简单地阐述一下rpm.deb.tar.gz的区别. rpm格式的软件包适用于基于Red Hat发行版的系统,如Red Hat Linux.SUSE.Fedora. deb格式的软件包则是适用于基于 ...
- C#中unit
整理的百度百科的一些关于UNIT的资料 中文名UINT 外文名typedef unsigned short UIN 性 质 32位无符号整数 应 用 是unsigned int派生出来的 ...
- 《VR入门系列教程》之22---GearVR SDK代码剖析
GearVR SDK代码剖析 接下来我们来了解一下GearVR开发包的底层代码,它底层的代码和之前在第三章中讲的桌面SDK代码非常类似,当然,也有许多不同的地方. 首先,我们看看如何构 ...
- PhpCms V9中的{date('Y-m-d',$r[inputtime])}问题解决方法
不少朋友会碰到这个问题:在PhpCms V9中的首页或者文章内容页调用发布时间{date('Y-m-d',$r[inputtime])}调用显示1970-01-01,然后尝试用截断的方法也没有成功,应 ...
- 关于JLINK调试时出现的 erasing range....的问题结果方法
声明:本人当然不是提倡盗版. 昨天在使用JLINK的时候遇到了这个问题,但是非常蹊跷,首先可以下载,但不能进入调试,到后来完成不能下载了. 这个问题的原因就是你得Keil检测到你锁使用的JLINK不是 ...