【BZOJ3167】[HEOI2013]SAO(动态规划)

题面

BZOJ

洛谷

题解

显然限制条件是一个\(DAG\)(不考虑边的方向的话就是一棵树了)。

那么考虑树型\(dp\),设\(f[i][j]\)表示当前点\(i\)在其子树内的排名为\(j\)的方案数。

每次考虑加入一棵子树,即考虑把\(f[v][k]\)加入到\(f[u][i]\)的贡献中。

分类讨论,如果\(v\)应当在\(u\)之前,枚举\(v\)的子树内一共有多少个点在\(u\)之前,那么假设\(u\)当前的序列长度为\(x\),\(v\)当前的序列长度为\(y\),枚举一共有\(j\)个\(v\)的子树内的点在\(u\)之前。

那么此时的方案数就是:\(f[u][i+j]\leftarrow {i+j-1\choose i-1}*f[u][i]*f[v][k]*{y-j+x-i\choose x-i}\)

然后我们来学习枚举(来写假的pascal代码)

for i:=1 to x do
for k:=1 to y do
for j:=k to y do
f[u][i+j]+=f[u][i]*f[v][k]*C[i+j-1][i-1]*C[x+y-i-j][x-i]

似乎这个\(k\)只在\(f[v][k]\)中出现过???

那么我们换一下

for i:=1 to x do
for j:=1 to y do
for k:=1 to j do
f[u][i+j]+=f[u][i]*f[v][k]*C[i+j-1][i-1]*C[x+y-i-j][x-i]

发现把\(f[v]\)数组前缀和一下底下这个玩意就可以做到\(O(1)\)转移啦。

而如果\(v\)要放在\(u\)之后也是类似的。

还是枚举有多少个放在\(u\)之前,那么这一部分的贡献是没变的,只是转移的时候的范围要变一变。

for i:=1 to x do
for k:=1 to y do
for j:=0 to k-1 do
f[u][i+j]+=f[u][i]*f[v][k]*C[i+j-1][i-1]*C[x+y-i-j][x-i]

还是换一下

for i:=1 to x do
for j:=0 to y do
for k:=i+1 to y do
f[u][i+j]+=f[u][i]*f[v][k]*C[i+j-1][i-1]*C[x+y-i-j][x-i]

这样子上面两层循环枚举的都是子树大小,因此全局总的复杂度就是\(O(n^2)\)啦。

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
#define MOD 1000000007
#define MAX 1010
void add(int &x,int y){x+=y;if(x>=MOD)x-=MOD;}
inline int read()
{
int x=0;bool t=false;char ch=getchar();
while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
if(ch=='-')t=true,ch=getchar();
while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
return t?-x:x;
}
struct Line{int v,next,w;}e[MAX<<1];
int h[MAX],cnt;
inline void Add(int u,int v,int w){e[cnt]=(Line){v,h[u],w};h[u]=cnt++;}
void init(){memset(h,0,sizeof(h));cnt=1;}
int n,C[MAX][MAX];char ch[2];
int f[MAX][MAX],sz[MAX],tmp[MAX];
void dfs(int u,int ff)
{
f[u][1]=1;sz[u]=1;
for(int i=h[u];i;i=e[i].next)
{
int v=e[i].v;if(v==ff)continue;
dfs(e[i].v,u);
for(int a=1;a<=sz[u];++a)
for(int b=0;b<=sz[v];++b)
if(e[i].w)
add(tmp[a+b],1ll*f[u][a]*f[v][b]%MOD*C[a+b-1][a-1]%MOD*C[sz[u]+sz[v]-a-b][sz[u]-a]%MOD);
else
add(tmp[a+b],1ll*f[u][a]*(f[v][sz[v]]-f[v][b]+MOD)%MOD*C[a+b-1][a-1]%MOD*C[sz[u]+sz[v]-a-b][sz[u]-a]%MOD);
sz[u]+=sz[v];
for(int j=1;j<=sz[u];++j)f[u][j]=tmp[j],tmp[j]=0;
}
for(int j=1;j<=sz[u];++j)add(f[u][j],f[u][j-1]);
}
int main()
{
for(int i=0;i<MAX;++i)C[i][0]=1;
for(int i=1;i<MAX;++i)
for(int j=1;j<=i;++j)C[i][j]=(C[i-1][j]+C[i-1][j-1])%MOD;
int T=read();
while(T--)
{
init();n=read();
for(int i=1,u,v;i<n;++i)
{
u=read()+1;scanf("%s",ch);v=read()+1;
if(ch[0]=='<')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]);
}
return 0;
}

【BZOJ3167】[HEOI2013]SAO(动态规划)的更多相关文章

  1. bzoj3167 [Heoi2013]Sao

    传送门 这题神坑啊……明明是你菜 首先大家都知道原题等价于给每个点分配一个$1$~$n$且两两不同的权值,同时还需要满足一些大于/小于关系的方案数. 先看一眼数据范围,既然写明了$n\le 1000$ ...

  2. [BZOJ3167][HEOI2013]SAO[树dp+组合数学]

    题意 给定 \(n\) 个节点和 \(n-1\) 个限制,每个节点有一个权值,每个限制形如:\(a_i< a_j\) ,问有多少个 \(1\) 到 \(n\) 排列满足要求. \(n\leq 1 ...

  3. 【BZOJ3167/4824】[Heoi2013]Sao/[Cqoi2017]老C的键盘

    [BZOJ3167][Heoi2013]Sao Description WelcometoSAO(StrangeandAbnormalOnline).这是一个VRMMORPG,含有n个关卡.但是,挑战 ...

  4. 3167: [Heoi2013]Sao [树形DP]

    3167: [Heoi2013]Sao 题意: n个点的"有向"树,求拓扑排序方案数 Welcome to Sword Art Online!!! 一开始想错了...没有考虑一个点 ...

  5. P4099 [HEOI2013]SAO

    P4099 [HEOI2013]SAO 贼板子有意思的一个题---我()竟然没看题解 有一张连成树的有向图,球拓扑序数量. 树形dp,设\(f[i][j]\)表示\(i\)在子树中\(i\)拓扑序上排 ...

  6. BZOJ 3167: [Heoi2013]Sao

    3167: [Heoi2013]Sao Time Limit: 30 Sec  Memory Limit: 256 MBSubmit: 96  Solved: 36[Submit][Status][D ...

  7. P4099 [HEOI2013]SAO(树形dp)

    P4099 [HEOI2013]SAO 我们设$f[u][k]$表示以拓扑序编号为$k$的点$u$,以$u$为根的子树中的元素所组成的序列方案数 蓝后我们在找一个以$v$为根的子树. 我们的任务就是在 ...

  8. [HEOI2013]SAO(树上dp,计数)

    [HEOI2013]SAO (这写了一个晚上QAQ,可能是我太蠢了吧.) 题目说只有\(n-1\)条边,然而每个点又相互联系.说明它的结构是一个类似树的结构,但是是有向边连接的,题目问的是方案个数,那 ...

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

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

随机推荐

  1. 替换iframe的内容

    一般就是点个按钮然后在不跳转页面的情况下显示另外一个页面的内容,显示的速度比较快,ifream还算是常用的吧 用的时候实现方式有以下几种, 1.替换src路径(觉得麻烦,没接触过,就不这样干了) 2. ...

  2. Python_内置函数之round的幺蛾子

    pycharm运行结果 1 ret = round(0.5) print(ret) >>> 0 ret1 = round(1.5) print(ret1) >>> ...

  3. pip ipython启动错误 Fatal error in launcher: Unable to create process using

    完整的错误提示: C:\Users\yyy>ipython3Fatal error in launcher: Unable to create process using '"c:\u ...

  4. scroll滚动条样式修改

    一般我们有两种情况会出现滚动条,一种是overflow,一种是使用scroll. 当我们需要改变这个滚动条样式的时候,我们需要做以下的修改: html: <div id="style- ...

  5. HTML中的几种空格

    HTML提供了5种空格实体(space entity),它们拥有不同的宽度,非断行空格( )是常规空格的宽度,可运行于所有主流浏览器.其他几种空格(       ‌‍)在不同浏览器中宽度各异.     ...

  6. 428.x的n次幂

    实现 pow(x,n) 不用担心精度,当答案和标准输出差绝对值小于1e-3时都算正确 样例 Pow(2.1, 3) = 9.261 Pow(0, 1) = 0 Pow(1, 0) = 1 挑战 O(l ...

  7. 工程下CmakeLists.txt

    2.工程下Cmake 本小节的任务是让上一小结的程序更像一个工程: 为工程添加一个子目录 src,用来放置工程源代码 : 添加一个子目录doc,用来放置这个工程的文档 hello.txt: 在工程目录 ...

  8. 游标cursor案例

  9. pojo类自动生成序列化ID

    自动生成序列化ID

  10. git fetch 更新远程代码到本地仓库

    理解 fetch 的关键, 是理解 FETCH_HEAD,FETCH_HEAD指的是: 某个branch在服务器上的最新状态’.这个列表保存在 .Git/FETCH_HEAD 文件中, 其中每一行对应 ...