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;
else
for(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. UOJ 做题记录

    UOJ 做题记录 其实我这么弱> >根本不会做题呢> > #21. [UR #1]缩进优化 其实想想还是一道非常丝播的题目呢> > 直接对于每个缩进长度统计一遍就好 ...

  2. project euler做题记录

    ProjectEuler_做题记录 简单记录一下. problem 441 The inverse summation of coprime couples 神仙题.考虑答案为: \[\begin{a ...

  3. Sam做题记录

    Sam做题记录 Hihocoder 后缀自动机二·重复旋律5 求一个串中本质不同的子串数 显然,答案是 \(\sum len[i]-len[fa[i]]\) Hihocoder 后缀自动机三·重复旋律 ...

  4. 退役IV次后做题记录

    退役IV次后做题记录 我啥都不会了.... AGC023 D 如果所有的楼房都在\(S\)同一边可以直接得出答案. 否则考虑最左最右两边的票数,如果左边>=右边,那么最右边会投给左边,因为就算车 ...

  5. 退役III次后做题记录(扯淡)

    退役III次后做题记录(扯淡) CF607E Cross Sum 计算几何屎题 直接二分一下,算出每条线的位置然后算 注意相对位置这个不能先搞出坐标,直接算角度就行了,不然会卡精度/px flag:计 ...

  6. 退役II次后做题记录

    退役II次后做题记录 感觉没啥好更的,咕. atcoder1219 历史研究 回滚莫队. [六省联考2017]组合数问题 我是傻逼 按照组合意义等价于\(nk\)个物品,选的物品\(\mod k\) ...

  7. BJOI做题记录

    BJOI做题记录 终于想起还要做一下历年省选题了2333 然而咕了的还是比做了的多2333 LOJ #2178. 「BJOI2017」机动训练 咕了. LOJ #2179. 「BJOI2017」树的难 ...

  8. FJOI2017前做题记录

    FJOI2017前做题记录 2017-04-15 [ZJOI2017] 树状数组 问题转化后,变成区间随机将一个数异或一,询问两个位置的值相等的概率.(注意特判询问有一个区间的左端点为1的情况,因为题 ...

  9. [日记&做题记录]-Noip2016提高组复赛 倒数十天

    写这篇博客的时候有点激动 为了让自己不颓 还是写写日记 存存模板 Nov.8 2016 今天早上买了两个蛋挞 吃了一个 然后就做数论(前天晚上还是想放弃数论 但是昨天被数论虐了 woc noip模拟赛 ...

随机推荐

  1. Optional容器类

    一.Optional 容器类:用于尽量避免空指针异常 方法 /* * Optional.of(T t) : 创建一个 Optional 实例 * Optional.empty() : 创建一个空的 O ...

  2. Java面向对象系列(10)- 什么是多态

    多态 即同一方法可以根据发送对象的不同而采取不同的行为方式 一个对象的实际类型是确定的,但可以指向对象的引用类型有很多 多态存在的条件 有继承关系 子类重写父类方法 父类引用指向子类对象 注意:多态是 ...

  3. jmeter调度器的使用

    前言 使用jmeter 做压测的时候,希望对一个接口持续压测 10 分钟或者半小时,可以使用调度器设置持续压测时间. https://www.cnblogs.com/yoyoketang/p/1415 ...

  4. 虚拟机安装配置centos7

    安装 https://blog.csdn.net/babyxue/article/details/80970526 主机环境预设 更换国内yum源 epel源 https://www.cnblogs. ...

  5. 鸿蒙内核源码分析(原子操作篇) | 是谁在为原子操作保驾护航 | 百篇博客分析OpenHarmony源码 | v34.02

    百篇博客系列篇.本篇为: v34.xx 鸿蒙内核源码分析(原子操作篇) | 谁在为原子操作保驾护航 | 51.c.h .o 本篇说清楚原子操作 读本篇之前建议先读鸿蒙内核源码分析(总目录)系列篇. 基 ...

  6. P3175-[HAOI2015]按位或【min-max容斥,FWT】

    正题 题目链接:https://www.luogu.com.cn/problem/P3175 题目大意 开始有一个\(n\)位二进制数\(s=0\),每次有\(p_i\)概率选取数字\(i\)让\(s ...

  7. P7514-[省选联考2021A/B卷]卡牌游戏【贪心】

    正题 题目链接:https://www.luogu.com.cn/problem/P7514 题目大意 给出\(n\)个卡牌有\(a_i/b_i\),开始都是\(a_i\)朝上,将不超过\(m\)张卡 ...

  8. mybatis本地缓存&分布式缓存干货分享

    前言:干货记录学习mybatis实际开发中缓存的使用. 环境: springboot2.X + mybatis3.x Mybatis是一款持久层框架,它提供了一级缓存和二级缓存. 名词解释 一级缓存( ...

  9. 记typora美化----让文章更加优美

    前言 昨晚偶然间看到一篇介绍记笔记工具以及如何美化的视频,突发奇想我打算也写一篇记录一下自己的美化过程,并会把自己使用的插件,样式文件等提供在下方,觉得不错得可以直接拿去使用,只希望观众能够一键3连, ...

  10. NLP与深度学习(六)BERT模型的使用

    1. 预训练的BERT模型 从头开始训练一个BERT模型是一个成本非常高的工作,所以现在一般是直接去下载已经预训练好的BERT模型.结合迁移学习,实现所要完成的NLP任务.谷歌在github上已经开放 ...