P4099 [HEOI2013]SAO

类型:树形 \(\text{DP}\)

这里主要补充一下 \(O(n^3)\) 的 \(\text{DP}\) 优化的过程,基础转移方程推导可以参考其他巨佬的博客(题解)。

令 \(f[x][p]\) 表示在以 \(x\) 为根的子树中,\(x\) 在拓扑序排在第 \(p\) 个时的方案数。

转移中设 \(x\) 在已经合并的拓扑序中排名为 \(p_1\) ,将要合并的子树(以 \(ver\) 为根)中 \(ver\) 排名为 \(p_2\) ,合并后 \(x\) 排名为 \(p_3\) 。

列出转移方程:(为了表示方便略去了取模操作)

  • 若 \(x < ver\) 即 \(x\) 应在 \(ver\) 之前,\(p_1<p_2\) 。
for(p1 = [1,siz[x]])for(p2 = [1,siz[ver]])for(p3 = [p1,p1+p2-1])f[x][p3]+=f[x][p1]*f[ver][p2]*c[p3-1][p1-1]*c[siz[x]+siz[ver]-p3][siz[x]-p1];
  • 若 \(x > ver\) 即 \(x\) 应在 \(ver\) 之后,\(p_1>p_2\) 。
for(p1 = [1,siz[x]])for(p2 = [1,siz[ver]])for(p3 = [p1+p2,siz[x]+siz[ver]])f[x][p3]+=f[x][p1]*f[ver][p2]*c[p3-1][p1-1]*c[siz[x]+siz[ver]-p3][siz[x]-p1];

(更直观的转移方程:)

\[f[x][p3]+=f[x][p1]\times f[ver][p2]\times C_{p3-1}^{p1-1}\times C_{siz[x]+siz[ver]-p3}^{siz[x]-p1} \]

到此为止,你可以得到 \(40pts\) 的好成绩。

交换内外循环

可以观察到 \(p_2\) 在转移方程中只出现了一次,因此我们将 \(p_2\) 和 \(p_3\) 的循环交换,列出转移方程:

  • 若 \(x < ver\) 即 \(x\) 应在 \(ver\) 之前,\(p_1<p_2\) 。
for(p1 = [1,siz[x]])for(p3 = [p1,p1+siz[ver]-1])for(p2 = [p3-p1+1,siz[ver]])f[x][p3]+=f[x][p1]*f[ver][p2]*c[p3-1][p1-1]*c[siz[x]+siz[ver]-p3][siz[x]-p1];
  • 若 \(x > ver\) 即 \(x\) 应在 \(ver\) 之后,\(p_1>p_2\) 。
for(p1 = [1,siz[x]])for(p3 = [p1+1,p1+siz[ver]])for(p2 = [1,p3-p1])f[x][p3]+=f[x][p1]*f[ver][p2]*c[p3-1][p1-1]*c[siz[x]+siz[ver]-p3][siz[x]-p1];

前缀和优化去掉一层循环

通过上一步的交换,发现 \(f[x][p3]\) 累加中的 \(p2\) 是一段连续的,并且满足乘法结合律,联想到前缀和优化。

令 \(g[x][p]\) 表示在以 \(x\) 为根的子树中,\(x\) 在拓扑序排在 \(p\) 个时的方案数之和。

那么转移方程变为:

  • 若 \(x < ver\) 即 \(x\) 应在 \(ver\) 之前,\(p_1<p_2\) 。
for(p1 = [1,siz[x]])for(p3 = [p1,p1+siz[ver]-1])g[x][p3]+=g[x][p1]*(g[ver][siz[ver]]-g[ver][p3-p1])*c[p3-1][p1-1]*c[siz[x]+siz[ver]-p3][siz[x]-p1];
  • 若 \(x > ver\) 即 \(x\) 应在 \(ver\) 之后,\(p_1>p_2\) 。
for(p1 = [1,siz[x]])for(p3 = [p1+1,p1+siz[ver]])g[x][p3]+=g[x][p1]*g[ver][p3-p1]*c[p3-1][p1-1]*c[siz[x]+siz[ver]-p3][siz[x]-p1];

记得在最后加上:

for(int i=1;i<=siz[x];i++) g[x][i]+=g[x][i-1];

所以这道题 \(AC\) 了。

注:转移中为了维持方程的无后效性,应将 \(f\) 数组备份一遍。

\(100pts\) 完整代码:

#include<bits/stdc++.h>
using namespace std;
#define inf 0x3f3f3f3f
#define Maxn 1005
#define mod 1000000007
inline int rd()
{int x=0;char ch,t=0;while(!isdigit(ch = getchar())) t|=ch=='-';while(isdigit(ch)) x=x*10+(ch^48),ch=getchar();return x=t?-x:x;
}
int t,n,tot;
int dp[Maxn][Maxn],tmp[Maxn],c[Maxn][Maxn],siz[Maxn];
int hea[Maxn],nex[Maxn<<1],ver[Maxn<<1],edg[Maxn<<1];
void add(int x,int y,int d)
{ver[++tot]=y,nex[tot]=hea[x],hea[x]=tot,edg[tot]=d;
}
void dfs(int x,int fa)
{siz[x]=1,dp[x][1]=1;for(int i=hea[x];i;i=nex[i]){if(ver[i]==fa) continue;dfs(ver[i],x);memcpy(tmp,dp[x],sizeof(dp[x]));memset(dp[x],0,sizeof(dp[x]));if(edg[i])for(int p1=1;p1<=siz[x];p1++)for(int p3=p1;p3<=siz[ver[i]]+p1-1;p3++)dp[x][p3]=(dp[x][p3]+1ll*tmp[p1]*(dp[ver[i]][siz[ver[i]]]-dp[ver[i]][p3-p1]+mod)%mod*c[p3-1][p1-1]%mod*c[siz[x]+siz[ver[i]]-p3][siz[x]-p1]%mod)%mod;elsefor(int p1=1;p1<=siz[x];p1++)for(int p3=p1+1;p3<=siz[ver[i]]+p1;p3++)dp[x][p3]=(dp[x][p3]+1ll*tmp[p1]*dp[ver[i]][p3-p1]%mod*c[p3-1][p1-1]%mod*c[siz[x]+siz[ver[i]]-p3][siz[x]-p1]%mod)%mod;siz[x]+=siz[ver[i]];}for(int i=1;i<=siz[x];i++) dp[x][i]=(dp[x][i]+dp[x][i-1])%mod;
}
int main()
{//freopen(".in","r",stdin);//freopen(".out","w",stdout);c[1][0]=c[0][0]=1;for(int i=1;i<=1000;i++,c[i][0]=1)for(int j=1;j<=i;j++)c[i][j]=(c[i-1][j]+c[i-1][j-1])%mod;t=rd();char c;while(t--){n=rd();memset(hea,0,sizeof(hea)),tot=0;memset(siz,0,sizeof(siz));for(int i=1,x,y;i<n;i++){x=rd()+1,cin>>c,y=rd()+1;add(x,y,c=='<'),add(y,x,c=='>');}dfs(1,0);printf("%d\n",dp[1][n]);}//fclose(stdin);//fclose(stdout);return 0;
}

【做题记录】 [HEOI2013]SAO相关推荐

  1. 退役前的做题记录2.0

    退役前的做题记录2.0 最近在刷省选题......大致上是按照省份刷的. 不过上面的题目顺序是按照写题的顺序排列的,所以可能会有点乱哈. [BZOJ2823][AHOI2012]信号塔 最小圆覆盖,随 ...

  2. 概率期望题(期望 DP)做题记录

    概率期望题(期望 DP)做题记录 P3830 [SHOI2012]随机树 难点在于第二问:生成树的期望深度. 不 wei zhuo 捏,设 \(dp_{i,j}\) 表示已经有了 \(i\) 个叶子结 ...

  3. 数数题(计数类 DP)做题记录

    数数题(计数类 DP)做题记录 CF1657E Star MST 我们称张无向完全图是美丽的当且仅当:所有和 \(1\) 相连的边的边权之和等于这张完全图的最小生成树的边权之和. 完全图点数为 \(n ...

  4. CSDN 第六期编程竞赛做题记录

    CSDN 第六期编程竞赛做题记录 -- CSDN编程竞赛报名地址:https://edu.csdn.net/contest/detail/16 9.18周日闲来无视写一下 csdn 的编程题,每期编程 ...

  5. 退役前的做题记录5.0

    退役前的做题记录5.0 出于某种原因新开了一篇. [CodeChef]Querying on a Grid 对序列建立分治结构,每次处理\((l,mid,r)\)时,以\(mid\)为源点建立最短路树 ...

  6. Regional 做题记录 (50/50)

    写在前面 博主深感自己太弱了QAQ 于是有了一个刷水的想法,Regional的题目还是有很多考查思维的题目,所以这次是乱做50道思考题,可能会顺带做一些水题,这些题的简要题解会写到这篇博文里面,希望能 ...

  7. 2020.7月做题记录

    转眼就到了2020的下半年了-前方仍是一片茫然. 长期计划 prufer 序列 2020.07.02-2020.07.04 Problem Finished P2624 [HNOI2008]明明的烦恼 ...

  8. 退役前的做题记录1.0

    退役前的做题记录1.0 租酥雨最近很懒qwq,具体表现在写题的时候不想发题解了. 但是想想这样也不太好,就决定发个一句话(半句话到几句话不等)题解上来. 2018-09.18-2018-09.28 [ ...

  9. 【Pikachu】漏洞练习平台做题记录+原理解析(2.2)XSS姿势和技巧

    前言 Pikachu是一个带有漏洞的Web应用系统,在这里包含了常见的web安全漏洞. 如果你是一个Web渗透测试学习人员且正发愁没有合适的靶场进行练习,那么Pikachu可能正合你意. pikach ...

  10. 退役前的做题记录4.0

    退役前的做题记录4.0 最近主要在LOJ上写题 536. 「LibreOJ Round #6」花札 比较显然的二分图博弈模型,先手必胜当且仅当起始点一定在最大匹配中.连边可以对每种颜色以及数字建一个点 ...

最新文章

  1. Android Hacks:在代码中隐藏软键盘
  2. C++初始化和关闭roscpp节点
  3. django makemigrtions时出现no changes detected 解决方式
  4. linux基础——linux进程间通信(IPC)机制总结
  5. 17_android下xmlpull解析
  6. rsync推拉模型及结合inotify实现推模型自动同步
  7. 盘点程序员开发遇到的30个问题
  8. super与this关键字的区别
  9. Qt treeWidget 查找指定字段内容的条目并跳转到该条目
  10. myVariable是java标识符吗_java 标识符与变量
  11. HTML5类选择器使用,CSS选择器种类及使用方法
  12. ProPublica Illinois如何每天使用GNU Make加载1.4GB数据
  13. Javascript中的内置对象:RegExp对象
  14. Dom操作(标签--增、删、移动)
  15. 【毕设】ASP.net校友录毕业设计(源代码+论文+开题报告+答辩PPT)
  16. jQuery 开始动画,停止动画
  17. 2021全国研究生数学建模竞赛E题思路
  18. java驱动刷机_ProductTool(炬力芯片刷机工具+驱动) v5.46 中文安装免费版
  19. Unparseable date: xxxxxx
  20. android官方模拟器下载安装,网易MuMu模拟器

热门文章

  1. zen服务器芯片,服务器版Zen处理器简直大杀器:32核64线程,8通道DDR4内存
  2. 算法设计与分析——回溯法——n皇后问题
  3. 算法设计与分析——递归与分治策略——循环日程赛
  4. 7-3 银行家算法--综合 (50 分)(思路+详解+分析输入)宝宝们 加油
  5. 网络计算机室电源线怎么布,网吧综合布线(电源和网络)经验谈
  6. [蓝桥杯2015决赛]积分之迷-枚举(水题)
  7. 辅助类KeyNode
  8. PTA天梯赛L1-006 连续因子 (20分)
  9. 数据结构与算法-- 广度优先打印二叉树
  10. 广东省计算机媒体大赛,广东省大学生计算机设计大赛