BZOJ 4011 HNOI2015 落忆枫音 DAG上的dp(实际上重点在于分析)
题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=4011
题意概述:给出一张N点的DAG(从1可以到达所有的点),点1的入度为0。现在加一条原图没有的边,问有多少种方案可使这张图变成一棵以1为根的有向树(即每个点的父亲指向自己)。
N<=100000,M<=min(200000,N(N-1)/2).
实际上这个题主要在分析(感觉终于开始自己做出省选题了)。
先看没有加边的情况,yy一下你发现这种情况的答案就是所有rd(入度)不为0的点rd相乘。道理是只要给每个点指定一个父亲,由于原图是DAG,相当于逆着边走,由于题目有保证1可以到达每个点,所以每个点一定可以反着走到1。
加边的情况?注意到加边之后可能还是DAG,一样的处理。如果不是DAG说明有环。答案分成两部分,不用新加的边的方案+用新加的边的合法方案。新加的边的合法方案又等于新加边所有方案-不合法方案(所有方案指的是父亲乱指,不合法方案指的是指出了环)。
重点在于计算不合法方案数。来分析一下环的性质,可以发现新加的边一定在环上,且我们已经计算的方案中任意一个点的rd为1,这种情况下如果图不连通可以有很多个环,但是所有环一定经过新加的边所以只有一个环。于是暴力地我们可以枚举所有的环,把环上所有点的rd变成1,其它所有点的rd相乘,得到的方案数就是这个环对当前答案的不合法贡献,减掉。
这个算法随便一卡就成了O(?反正是个指数级别) 的优秀算法了,怎么优化呢?令加的边为x->y,可以发现任意一个环一定是从y出发经过一些点走到x经过x->y这条边回到y,也就是说环的数量就是原图中y到x的路径数量。注意到所有点的rd之积mul是不变的,在暴力算法中每条环上的点rd变成1,也就对应y到x的路径上的每一个点rd变成1,如果y到x的一条路径上的rd乘积为_mul,那么这条路径对不合法答案的贡献就是mul/_mul,最后是所有的不合法贡献相加之后从答案中扣除,所以可以设计出这样的dp方程:
令f(i)表示i到x的路径上的点对答案的不合法贡献数,f(i)=sum{ f(j) | j->i } / rd[i]。(实际上这个dp就是对暴力的一个优化而已)
特殊判断一些情况即可。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<queue>
#include<set>
#include<map>
#include<vector>
#include<cctype>
using namespace std;
const int maxn=;
const int maxm=;
const int mo=; int N,M,X,Y;
struct edge{ int to,next; }E[maxm];
int first[maxn],np,rd[maxn],sccno[maxn],sccsz[maxn],scc_cnt,dfs_clock,dfn[maxn],low[maxn];
int stk[maxn],top,inv[maxn],f[maxn],ID,mul; void add_edge(int u,int v)
{
E[++np]=(edge){v,first[u]};
first[u]=np;
}
void data_in()
{
scanf("%d%d%d%d",&N,&M,&X,&Y);
int x,y;
for(int i=;i<=M;i++){
scanf("%d%d",&x,&y);
rd[y]++;
add_edge(x,y);
}
add_edge(X,Y);
inv[]=;
for(int i=;i<=N;i++)
inv[i]=1ll*inv[mo%i]*(mo-mo/i)%mo;
}
void tarjan_scc(int i)
{
low[i]=dfn[i]=++dfs_clock;
stk[++top]=i;
for(int p=first[i];p;p=E[p].next){
int j=E[p].to;
if(dfn[j]){
if(!sccno[j]) low[i]=min(low[i],dfn[j]);
continue;
}
tarjan_scc(j);
low[i]=min(low[i],low[j]);
}
if(low[i]==dfn[i]){
scc_cnt++;
while(){
sccno[stk[top]]=scc_cnt;
sccsz[scc_cnt]++;
if(stk[top--]==i) break;
}
}
}
int dp(int i)
{
if(f[i]) return f[i];
if(i==X) return f[i]=mul;
for(int p=first[i];p;p=E[p].next){
int j=E[p].to;
if(sccno[j]!=ID||i==X&&j==Y) continue;
f[i]=(f[i]+dp(j))%mo;
}
return f[i]=1ll*f[i]*inv[rd[i]]%mo;
}
void work()
{
int ans=;
for(int i=;i<=N;i++) ans=1ll*ans*rd[i]%mo;
if(Y!=){
ans=1ll*ans*inv[rd[Y]]%mo*(rd[Y]+)%mo;
tarjan_scc();
int MAX=;
for(int i=;i<=N;i++)
if(sccsz[sccno[i]]>MAX) MAX=sccsz[sccno[i]],ID=sccno[i];
if(MAX>){
rd[X]=rd[Y]=mul=;
for(int i=;i<=N;i++) mul=1ll*mul*rd[i]%mo;
ans=(ans-dp(Y)+mo)%mo;
}
}
printf("%d\n",ans);
}
int main()
{
data_in();
work();
return ;
}
BZOJ 4011 HNOI2015 落忆枫音 DAG上的dp(实际上重点在于分析)的更多相关文章
- BZOJ 4011: [HNOI2015]落忆枫音( dp )
DAG上有个环, 先按DAG计数(所有节点入度的乘积), 然后再减去按拓扑序dp求出的不合法方案数(形成环的方案数). ---------------------------------------- ...
- BZOJ 4011: [HNOI2015]落忆枫音 计数 + 拓扑排序
Description 「恒逸,你相信灵魂的存在吗?」 郭恒逸和姚枫茜漫步在枫音乡的街道上.望着漫天飞舞的红枫,枫茜突然问出 这样一个问题. 「相信吧.不然我们是什么,一团肉吗?要不是有灵魂……我们 ...
- BZOJ 4011 HNOI2015 落忆枫音
AC通道:http://www.lydsy.com/JudgeOnline/problem.php?id=4011 题目很长,写得也很有诗意与浪漫色彩,让我们不禁感叹出题人是一个多么英俊潇洒的人. 所 ...
- 4011: [HNOI2015]落忆枫音
4011: [HNOI2015]落忆枫音 链接 分析: 原来是一个DAG,考虑如何构造树形图,显然可以给每个点找一个父节点,所以树形图的个数就是$\prod\limits_u deg[u]$. 那么加 ...
- 【BZOJ】4011: [HNOI2015]落忆枫音
题目链接:http://blog.csdn.net/popoqqq/article/details/45194103 写代码的时候也没有很清晰....具体看这里吧 #include<iostre ...
- [BZOJ4011][HNOI2015] 落忆枫音(学习笔记) - 拓扑+DP
其实就是贴一下防止自己忘了,毕竟看了题解才做出来 Orz PoPoQQQ 原文链接 Description 背景太长了 给定一个DAG,和一对点(x, y), 在DAG中由x到y连一条有向边,求生成树 ...
- 【bzoj4011】[HNOI2015]落忆枫音 容斥原理+拓扑排序+dp
题目描述 给你一张 $n$ 个点 $m$ 条边的DAG,$1$ 号节点没有入边.再向这个DAG中加入边 $x\to y$ ,求形成的新图中以 $1$ 为根的外向树形图数目模 $10^9+7$ . 输入 ...
- 【题解】 [HNOI2015]落忆枫音 (拓扑排序+dp+容斥原理)
原题戳我 Solution: (部分复制Navi_Aswon博客) 解释博客中的两个小地方: \[\sum_{\left(S是G中y→x的一条路径的点集\right))}\prod_{2≤j≤n,(j ...
- bzoj4011[HNOI2015]落忆枫音 dp+容斥(?)
4011: [HNOI2015]落忆枫音 Time Limit: 10 Sec Memory Limit: 512 MBSubmit: 1125 Solved: 603[Submit][Statu ...
随机推荐
- Unity3d-制作粒子光环特效
http://blog.csdn.net/ozhangseno/article/details/70799611
- python 实现远程上传文件夹
python2 upload.py "ip" "root" "password" "22" "Only Pro ...
- 关于刷新同级layer弹框的解决方法
在项目中遇到这种情况: 父页面点击详情,layer.open一个子页面A,子页面里面又存在操作按钮,点击使用parent.layer.open在打开一个子页面B,子页面B点击提交操作成功要刷新子页面A ...
- 菜鸟崛起 DB Chapter 3 MySQL 5.6的基本操作
3 MySQL的基本操作 上面我们学习一如何安装数据库,那么这节我们来认识一下数据库: 我们在MySQL安装后,在data目录下会自动生成几个必须的数据库,可以使用SHOW DATABASES语句 ...
- CentOS 7 安装oracle 11G
一.安装Oracle前准备 首先要设置主机名,并在/etc/hosts下解析. 镜像没挂全,导致缺少包pdksh-5.2.14.compat-libstdc++-33-3.2.3 1.创建运行orac ...
- SmallMQ实现发布
最近一直学习,主要处理java的分布式,MQ,RPC,通信,数据库,缓存等方向. 一般现在的MQ都是企业级的,庞大,功能齐全.最主要是代码量大,对于我们这些小程序员而言,太大,修改困难,修复更加困难, ...
- ABAP术语-BOR (Business Object Repository )
BOR (Business Object Repository ) 原文:http://www.cnblogs.com/qiangsheng/archive/2007/12/25/1013523.ht ...
- 修改zabbix字体格式
环境: centos7 zabbix3.2 1.获取喜欢的字体格式文件(喜欢别的字体也可以去网上下载) 通常都是ttf格式,可直接在windows下获取C:\Windows\Fonts 2.配置zab ...
- Laravel 集合的处理
其中的方法有: $arrs = collect($arr)->collapse()->collapse() //去除最外一层数组,不论最外层数组时否有值,都会去除掉 collect($ar ...
- Windows下安装最新版的MongoDB
最近学习爬虫需要用到MongoDB来存储数据,在安装过程遇到了一些坑,在这里总结一些. 安装环境:Windows 10 安装步骤: 1.下载安装文件 下载地址:https://www.mongodb. ...