[HEOI2013]SAO ——计数问题
题目大意:
Welcome to SAO ( Strange and Abnormal Online)。这是一个 VR MMORPG, 含有 n 个关卡。但是,挑战不同关卡的顺序是一个很大的问题。
有 n – 1 个对于挑战关卡的限制,诸如第 i 个关卡必须在第 j 个关卡前挑战, 或者完成了第 k 个关卡才能挑战第 l 个关卡。并且,如果不考虑限制的方向性, 那么在这 n – 1 个限制的情况下,任何两个关卡都存在某种程度的关联性。即, 我们不能把所有关卡分成两个非空且不相交的子集,使得这两个子集之间没有任 何限制。
对于每个数据,输出一行一个整数,为攻克关卡的顺序方案个数,mod 1,000,000,007 输出。
题目翻译:
发现最后一句话就是说:这是一棵树形图。
所以我们现在有了一棵树,只是边是有向边,挑战的限制就是边的方向,我们必须把所有指向x0的关卡全部通过,才能通过x0关卡。
其实,所有指向x0的边就是它的度数,所以可以看出来,
这个题是让我们求这个树形图有多少种拓扑序。
分析:
这个题即使看了题解也是理解了半天。网上题解也不是很多,做法类似。
树形计数问题,可以用树形DP,首先我们可以先尝试定义一维,定义f[i]表示以i为根的子树的拓扑序有多少种,现在我们需要考虑怎样将若干个儿子的值转移到父亲上。
发现,如果把两个儿子的拓扑序,看做是两个区间,那么我们做的其实是一个区间合并的操作。
但是由于边其实是有向的,(虽然我们是无向边建树)实际边的方向还决定父亲,该儿子的真正完全的拓扑序谁在前,谁在后。就是说,要先过了父亲,还是先过了儿子。
非常无从下手的感觉。我们需要再定义一维。
于是我们这样定义:
f[i][j]表示,在以i为根的子树中,根节点i排在第j位的拓扑序的种类数。(其实所有的拓扑序就是f[i][1-size])
可以发现,j不同时,方案数一定是独立的。
现在我们要考虑转移:
当我们循环到x的一个儿子y的时候,size[x]记录的是当前x与其前面所有儿子子树的size和,就是还没有包括y
那么前面说了,就是一个区间合并,我们以x的位置作为断点考虑合并。
先分类(因为我们无向边建树,但是实际上是有向边。)
①x<y 即先通过x,再通过y。
这个时候,拓扑序合并后x的排名一定在y的前面。
对于f[x][k],最终x前面有k-1个元素。可以从f[x][i](1<=i<=min(k,size))和 f[y][j](j的范围随后再确定)转移过来。转移之后,区间内共有size[x]+size[y]个数
就是说,我在合并后的拓扑序中,先从之前的f[x][i]中的方案数中拿出若干种,放进大区间里,再从f[y][j]里选择一些方案数,放进大区间里。所以这里i一定小于等于k
前k-1个位置,从之前的数中先挑出i-1个位置,有C(k-1,i-1)种选法,
后size[x]+size[y]-k个位置(不算x), 已经选择了i-1个数,还剩下size[x]-i个数(x自己不算),有C(size[x]+size[y]-k,size[x]-i)种选法。
再乘上每个选上的集合中自己的变化,也就是f[x][i]自己本身(类似多重集合的排列)
剩下的位置就是f[y][j]的了,不需要再乘组合数,只需乘上f[y][j]就好。
现在我们要确定j的取值范围:
对于x<y的情况,x之前的数,我们已经填了i-1个位置,还剩下k-i个位置要填,
为了使得y在x的后面,而y之前还能放j-1个数,所以要使得:j-1>=k-i,当然j<=size[y]
所以,j的循环范围是,k-i+1<=j<=size[y]
所以,对于x<y的情况,我们可以列出状态转移的方程是:
f[x][k]=(1<=i<=min(k,size[x]))(k-i+1<=j<=size[y]) f[x][i]*c[k-1][i-1]*c[size[x]+size[y]-k][size[x]-i]*f[y][j]
这样子,发现每次要循环一遍j,复杂度是O(n^4)的,直接挂掉。。。
又发现,对于同一个y,我们好像加的是同一些树,循环的是同一些j。。。
我们把这个式子用乘法分配律提出来一下:
f[x][k]=(1<=i<=min(k,size[x])) f[x][i]*c[k-1][i-1]*c[size[x]+size[y]-k][size[x]-i]*(f[y][k-i+1]+...f[y][size[y]])
所以,加粗部分是可以通过一个前缀合优化处理的,复杂度变成O(1)。
①x>y 即先通过y,再通过x。
其实是同理的。f[x][i](1<=i<=min(k,size)),i的范围没有变。
但是由于要保证y在x的前面,j-1个元素,必然不能填满k-i个位置
所以,j-1<k-i (注意是小于,不是小于等于,因为还有一个位置是y自己,所以要用j-1个位置填不满k-i个位置)并且j>=1
所以这里的状态转移方程是:
f[x][k]=(1<=i<=min(k,size[x]))(1<=j<=k-i) f[x][i]*c[k-1][i-1]*c[size[x]+size[y]-k][size[x]-i]*f[y][j]
同理可以乘法分配律,前缀和优化。
详见代码:
#include<bits/stdc++.h> #define ull unsigned long long #define ll long long using namespace std; +; ; int n,t; struct node{ int nxt,to,val; }bian[*N]; int head[N],cnt; void add(int x,int y,int z) { bian[++cnt].to=y; bian[cnt].nxt=head[x]; bian[cnt].val=z; head[x]=cnt; } ull f[N][N],sumdp[N][N]; ull c[N][N]; int size[N]; bool vis[N]; void dfs(int x) { size[x]=; f[x][]=; vis[x]=; for(int o=head[x];o;o=bian[o].nxt) { int y=bian[o].to; if(!vis[y]) { dfs(y); if(bian[o].val)//......x...y { ;k--) { ull sum=; ;i<=min(size[x],k);i++) { int l=k-i,r=size[y]; ull del=(sumdp[y][size[y]]+mod-sumdp[y][k-i])%mod;//前缀和差值 if(l<r) { ull q=(f[x][i]*del)%mod,p=(c[k-][i-]*c[size[x]+size[y]-k][size[x]-i])%mod; p*=q;p=p%mod;sum+=p;sum%=mod;//这里,必须四个数分别计算并取模,否则会爆long long } } f[x][k]=sum; } } else//.........y...x { ;k--) { ull sum=; ;i<=min(size[x],k-);i++) { int r=min(size[y],k-i); ull del=sumdp[y][r]; ull q=(f[x][i]*del)%mod,p=(c[k-][i-]*c[size[x]+size[y]-k][size[x]-i])%mod; p*=q;p=p%mod;sum+=p;sum%=mod; } f[x][k]=sum; } } size[x]+=size[y]; } } ;i<=size[x];i++)//处理完了x,赋值前缀和,以便后续使用 sumdp[x][i]=(sumdp[x][i-]+f[x][i])%mod; } void clear()//清空 { cnt=; ;i<=n;i++) { head[i]=;vis[i]=; size[i]=; ;j<=n;j++) sumdp[i][j]=,f[i][j]=; } } int main() { c[][]=; ;i<=;i++) { c[i][]=; ;j<=i;j++) c[i][j]=(c[i-][j]+c[i-][j-])%mod; }//1000的范围,组合数打表 cin>>t; while(t) { scanf("%d",&n); clear(); int x,y; ]; ;i<=n-;i++) { scanf("%d%s%d",&x,q,&y); x++,y++;//变成以1开始 ]=='<') { add(x,y,); add(y,x,); } else{ add(y,x,); add(x,y,); }//建无向边,x,y距离是1,表示x<y 先过x后过 y } dfs(); ull ans=; ;i<=size[];i++) { ans=(ans+f[][i])%mod; }//方案数 printf("%llu\n",ans); t--; } ; }
基本思路和代码参考shadowice1984,https://www.luogu.org/blog/ShadowassIIXVIIIIV/solution-p4099
详细化了很多。
[HEOI2013]SAO ——计数问题的更多相关文章
- 3167: [Heoi2013]Sao [树形DP]
3167: [Heoi2013]Sao 题意: n个点的"有向"树,求拓扑排序方案数 Welcome to Sword Art Online!!! 一开始想错了...没有考虑一个点 ...
- 【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 ...
- P4099 [HEOI2013]SAO(树形dp)
P4099 [HEOI2013]SAO 我们设$f[u][k]$表示以拓扑序编号为$k$的点$u$,以$u$为根的子树中的元素所组成的序列方案数 蓝后我们在找一个以$v$为根的子树. 我们的任务就是在 ...
- 【BZOJ3167/4824】[Heoi2013]Sao/[Cqoi2017]老C的键盘
[BZOJ3167][Heoi2013]Sao Description WelcometoSAO(StrangeandAbnormalOnline).这是一个VRMMORPG,含有n个关卡.但是,挑战 ...
- [BZOJ3167][P4099][HEOI2013]SAO(树形DP)
题目描述 Welcome to SAO ( Strange and Abnormal Online).这是一个 VR MMORPG, 含有 n 个关卡.但是,挑战不同关卡的顺序是一个很大的问题. 有 ...
- luogu P4099 [HEOI2013]SAO
传送门 吐槽题目标题 这个依赖关系是个树,可以考虑树型dp,设f_i表示子树i的答案 因为这是个序列问题,是要考虑某个数的位置的,所以设\(f_{i,j}\)表示子树i构成的序列,i在第j个位置的方案 ...
- Luogu4099 HEOI2013 SAO 组合、树形DP
传送门 值得注意的是一般的DAG的拓扑序列数量是NP问题,所以不能直接入手 题目中给出的图可以看做是一个树形图,虽然方向比较迷.考虑使用树形图的性质 不妨任选一个点为根做树形DP,注意到数的位置与方案 ...
随机推荐
- 又到周末了,我们一起来研究【浏览器如何检测是否安装app】吧
前言 扯淡 这个月比较倒霉,我送了女朋友一台笔记本电脑作为生日礼物,结果15天一过电脑就坏了,悲剧的我还把电脑盒子给扔了!淘宝不给换更不给退 于是被女朋友臭骂了一过星期后,今天本来在公司有任务的,但是 ...
- CentOS(RedHat)命令行永久修改IP地址、网关、DNS
1.修改IP地址vim /etc/sysconfig/network-scripts/ifcfg-eth0DEVICE=eth0 #网卡名称BOOTPROTO=static #获取ip的方式(stat ...
- java 中间件
先说中间件:非底层操作系统软件.非业务应用软件,不是直接给最终用户使用的,不能直接给客户带来价值的软件,统称中间件.常见的有如下几种:服务中间件.集成中间件.数据中间件.消息中间件.安全中间件. 其中 ...
- DOS攻击和DDOS攻击有啥区别啊
DDOS是DOS攻击中的一种方法. DoS:是Denial of Service的简称,即拒绝服务,不是DOS操作系统,造成DoS的攻击行为被称为DoS攻击,其目的是使计算机或网络无法提供正常的服务. ...
- IOS 支付宝、微信回调传值给H5网页
这里用是的苹果原生和JS的交互 .有不明白JavaScriptCore框架的可以去网上搜索下这方面的资料很多废话不多说直接上代码 @protocol JSContextDelegate <JSE ...
- 在VS2012下不安装VS2010编译VS2010的工程
虽然一路追随这VISUAL SUTDIO在编程,但是断档的情况还是有的,最近一次硬盘问题使得安装了所有的VS2003-VS2012的机器硬盘挂了,无奈只能够安装了,不过觉得没啥用了,就安装一个VS20 ...
- OCP读书笔记(12) - 执行闪回数据库
闪回数据库使用的是闪回日志,闪回日志存在于闪回目录(也就是快速闪回区中)闪回日志:就是数据块修改之前的镜像,简称前像 1.查看闪回目录的位置:show parameter recovery 如果闪回目 ...
- 转发:iOS开发系列--触摸事件、手势识别、摇晃事件、耳机线控
-- iOS事件全面解析 转载来自崔江涛(KenshinCui) 链接:http://www.cnblogs.com/kenshincui/p/3950646.html 概览 iPhone的成功很大一 ...
- 关于awk的范围模式功能问题
关于awk的范围模式功能问题 man awk中这样写到 The pattern1, pattern2 form of an expression is called a range pattern. ...
- 安装Anaconda 之后使用ubuntu自带python
我们知道,Ubantu系统会自带python,当你在terminal窗口中输入python,就会显示默认安装的python的信息.比如我的16.04就自带了python2.7和3.5,但是安装了Ana ...