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 ...
随机推荐
- ES6 async await
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- Nginx从搭建到配置支持HTTPS
原文地址:https://www.xingkongbj.com/blog/nginx/nginx.html 安装 基础包 ububtu apt-get install build-essential ...
- Java分享笔记:关于Java反射机制
[1] 关于Java反射机制的概述 1.反射机制的概念:允许程序在执行期,借助于反射相关的API,取得任何类的内部信息,并能直接操作任意对象内部的属性和方法. 2.与反射相关的主要的API:java. ...
- Mac上从gitlab上拉项目实战总结
建立公钥,私钥 https://blog.csdn.net/jigongdajiang/article/details/65441923 2019-01-03 比较喜欢使用图形化界面
- springmvc重定向请求。
SpringMVC重定向传参数的实现(来自网友) 验证了我说的,从model层中拿来的数据,不管什么类型,都是通过隐含模型,中转,放入request中的.除非你特意把这些数据放到session域中. ...
- MFC下的DLL编程学习
1.DLL库与LIB库对比: 静态链接库Lib(Static Link Library),是在编译的链接阶段将库函数嵌入到应用程序的内部.如果系统中运行的多个应用程序都包含所用到的公共库函数,则必然造 ...
- 01-HTML深入
1.1 浏览器的工作原理 把一些标签解析成用户可视化的页面 1.2 HTML中的标签与元素 在HTML中以<xx>开始,以</xx>结束,比如<html>< ...
- PHP 十问
1.为了保证精度,Mysql中存钱数的字段用什么类型?PHP怎么处理浮点数精度 decimal数据类型来存储钱: 浮点数的精度有限.尽管取决于系统,PHP 通常使用 IEEE 754 双精度格式,则由 ...
- ruby URI类
一. URI require 'uri' uri = URI("http://foo.com/posts?id=30&limit=5#time=1305298413") # ...
- grep用法小结
用法 grep [OPTIONS] PATTERN [FILE...] grep [OPTIONS] -e PATTERN ... [FILE...] grep [OPTIONS] -f FILE . ...