bzoj 1093 缩点+DP
首先比较明显的是如果存在一个半连通子图,我们将其中的环缩成点,那么该图仍为半连通子图,这样我们就可以先将整张图缩点,重新构图,新图为拓扑图,记录每个新的点表示的强连通分量中点的个数num[i],那么我们就可以DP了,新图中的每一条链都为原图的半连通子图,这样我们找到新图中的最长链就行了,找入度为0的点dfs做树上DP,这样我们可以知道每个点的len[i]代表从这个点开始的最长链的长度,len[i]=max(len[son of i])+num[i],然后我们求出来了第一问,对于第二问,我们需要找len[i]=ans1的点做dfs,然后设ans[i]为以i为根的子树的方案数,那么ans[i]+=ans[son of i] (len[i]=len[son of i]+num[i]),因为我们需要找最长链上的点来更新答案,这样最后再累计答案就好了。
反思:开始题中说没有重边,但是没有考虑到重构图之后的图是可能有重边的,这样第二问的答案就可能会被重复累加,所以我们DP的时候可以维护一个栈,和每个栈中元素的父亲,这样对于一个点枚举子节点,如果子节点没有在栈中出现过,那么就累加答案,该子节点进栈,dfs最后的时候再弹出所有栈中x的子节点。
/**************************************************************
Problem: 1093
User: BLADEVIL
Language: C++
Result: Accepted
Time:1992 ms
Memory:45028 kb
****************************************************************/
//By BLADEVIL
#include <cstdio>
#include <algorithm>
#define maxn 200020
#define maxm 4000040
using namespace std;
int n,m,d39,l,tot,time,size;
int last[maxn],other[maxm],pre[maxm],stack[maxn],low[maxn],dfn[maxn],flag[maxn],col[maxn],num[maxn],in[maxn];
int len[maxn],ans[maxn],father[maxn];
int p1,p2;
void connect(int x,int y){
pre[++l]=last[x];
last[x]=l;
other[l]=y;
//if (x>n||y>n) printf("%d %d\n",x,y);
}
void tarjan(int x){
//printf("%d %d\n",x,fa);
low[x]=dfn[x]=++time;
stack[++tot]=flag[x]=x;
//for (int i=1;i<=tot;i++) printf("%d ",stack[i]); printf("\n");
for (int p=last[x];p;p=pre[p]){
if (!dfn[other[p]]) tarjan(other[p]),low[x]=min(low[x],low[other[p]]); else
if (flag[other[p]]) low[x]=min(low[x],dfn[other[p]]);
}
if (low[x]==dfn[x]){
int cur=-;
while (cur!=x){
cur=stack[tot--];
flag[cur]=;
col[cur]=size;
num[size]++;
}
size++;
}
}
void dfs(int x){
int cur=;
for (int p=last[x];p;p=pre[p]){
if (!len[other[p]]) dfs(other[p]);
cur=max(cur,len[other[p]]);
}
len[x]=cur+num[x];
//printf(" %d %d\n",x,len[x]);
}
void work(int x){
for (int p=last[x];p;p=pre[p])
if (len[other[p]]+num[x]==len[x]) {
if (flag[other[p]]) continue;
if (!ans[other[p]]) work(other[p]);
ans[x]+=ans[other[p]];
stack[++tot]=other[p]; flag[other[p]]=; father[other[p]]=x;
}
if (!ans[x]) ans[x]=;
ans[x]%=d39;
while (father[stack[tot]]==x) flag[stack[tot--]]=;
}
int main(){
int x,y;
scanf("%d%d%d",&n,&m,&d39); size=n+;
for (int i=;i<=m;i++) scanf("%d%d",&x,&y),connect(x,y);
for (int i=;i<=n;i++) if (!low[i]) tarjan(i);
//for (int i=1;i<=n;i++) printf("%d %d %d\n",col[i],low[i],dfn[i]);
for (int i=;i<=n;i++)
for (int p=last[i];p;p=pre[p])
if (col[i]!=col[other[p]]) connect(col[i],col[other[p]]),in[col[other[p]]]++;
//for (int i=n+1;i<size;i++) printf("|%d %d\n",i,num[i]);
for (int i=n+;i<size;i++) if (!in[i]) dfs(i);
//for (int i=n+1;i<size;i++) printf("|%d %d\n",i,len[i]);
for (int i=n+;i<size;i++) p1=max(p1,len[i]);
for (int i=n+;i<size;i++) if (len[i]==p1) work(i);
for (int i=n+;i<size;i++) if (len[i]==p1) (p2+=ans[i])%=d39;
//for (int i=n+1;i<size;i++) printf("|%d %d\n",i,ans[i]);
printf("%d\n%d\n",p1,p2);
return ;
}
bzoj 1093 缩点+DP的更多相关文章
- BZOJ 1093 [ZJOI2007] 最大半连通子图(强联通缩点+DP)
题目大意 题目是图片形式的,就简要说下题意算了 一个有向图 G=(V, E) 称为半连通的(Semi-Connected),如果满足图中任意两点 u v,存在一条从 u 到 v 的路径或者从 v 到 ...
- bzoj 1093 [ZJOI2007]最大半连通子图——缩点+拓扑
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=1093 缩点+拓扑,更新长度的时候维护方案数. 结果没想到处理缩点后的重边,这样的话方案数会算 ...
- BZOJ 1093 [ZJOI2007]最大半连通子图
1093: [ZJOI2007]最大半连通子图 Time Limit: 30 Sec Memory Limit: 162 MBSubmit: 1986 Solved: 802[Submit][St ...
- POJ3160 Father Christmas flymouse[强连通分量 缩点 DP]
Father Christmas flymouse Time Limit: 1000MS Memory Limit: 131072K Total Submissions: 3241 Accep ...
- [bzoj 1093][ZJOI2007]最大半联通子图(强联通缩点+DP)
题目:http://www.lydsy.com:808/JudgeOnline/problem.php?id=1093 分析: 首先肯定是先把强联通全部缩成一个点,然后成了一个DAG 下面要知道一点: ...
- BZOJ 1093 强连通缩点+DAG拓扑DP
缩点后在一个DAG上求最长点权链 和方案数 注意转移条件和转移状态 if (nowmaxn[x] > nowmaxn[v]) { ans[v] = ans[x]; nowmaxn[v] = no ...
- BZOJ 1093: [ZJOI2007]最大半连通子图( tarjan + dp )
WA了好多次... 先tarjan缩点, 然后题意就是求DAG上的一条最长链. dp(u) = max{dp(v)} + totu, edge(u,v)存在. totu是scc(u)的结点数. 其实就 ...
- bzoj 1093 [ ZJOI 2007 ] 最大半连通子图 —— 拓扑+DP
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=1093 先缩点,然后就是找最长链,DP一下即可: 注意缩点后的重边!会导致重复计算答案. 代码 ...
- bzoj 1093 [ZJOI2007]最大半连通子图(scc+DP)
1093: [ZJOI2007]最大半连通子图 Time Limit: 30 Sec Memory Limit: 162 MBSubmit: 2286 Solved: 897[Submit][St ...
随机推荐
- css3边框阴影效果
下面来说下css3阴影的语法: box-shadow:none | <shadow> [ , <shadow> ]* <shadow> = inset? & ...
- mstsc远程登录终端超出最大连接数的解决办法
1,.远程服务器有两个用户登录 2.第三个登录时提示:终端服务器超出了最大允许连接,这种情况怎么解决 A.通过运行命令来解决:运行输入mstsc /admin /v:IP:端口 敲回车来解决,这里的 ...
- java 基础 --匿名内部类-008
不全代码 interface Inter(){void show();} class Outer{补全代码} class OuterDemo{ public static void main(Stri ...
- 求csdn博客优良编辑方法
看见很多大牛的csdn博客编写的非常好,阅读体验也非常强.我就纳闷了,为啥我插公式也不行,插图片也不行呢... 插图片问题:图片不能复制招贴,否则在编辑的时候可以显示但是在发表之后就无法显示了.想要显 ...
- 第52天:offset家族、scroll家族和client家族的区别
一.offset家族 1.offsetWidth offsetHeight offsetLeft offsetTop offsetParent共同组成了offset家族,用来获取元素尺寸. offse ...
- 当提交的表单类型为multipart/form-data时 后台的dopost则不能使用 setCharset来进行解码了 需要单独对字段使用 原始的new String(req.name("ISO-8859-1"),"utf-8")形式解码了
当提交的表单类型为multipart/form-data时 后台的dopost则不能使用 setCharset来进行解码了 需要单独对字段使用 原始的new String(req.name(" ...
- 【bzoj3932】[CQOI2015]任务查询系统 离散化+主席树
题目描述 最近实验室正在为其管理的超级计算机编制一套任务管理系统,而你被安排完成其中的查询部分.超级计算机中的任务用三元组(Si,Ei,Pi)描述,(Si,Ei,Pi)表示任务从第Si秒开始,在第Ei ...
- windows 架设SVN服务器
想完整走一遍svn布置及使用流程,试完整理了一下: step 1:下载安装 1.安装SVN服务器,到http://subversion.apache.org/packages.html 上下载wind ...
- Tensorflow框架初尝试————搭建卷积神经网络做MNIST问题
Tensorflow是一个非常好用的deep learning框架 学完了cs231n,大概就可以写一个CNN做一下MNIST了 tensorflow具体原理可以参见它的官方文档 然后CNN的原理可以 ...
- [转载]php中sleep,flush,ob_flush函数介绍
<?phpecho str_pad(" ",1024);//当上面这句没有的时候浏览器没有任何输出 直到sleep函数设定的时间结束 才会输出//原因如下面截图for ($i ...