WA了好多次...

先tarjan缩点, 然后题意就是求DAG上的一条最长链. dp(u) = max{dp(v)} + totu, edge(u,v)存在. totu是scc(u)的结点数. 其实就是记忆化搜一下...重边就用set判一下

-------------------------------------------------------------------------------------------

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<stack>
#include<iostream>
#include<cctype>
#include<set>
 
using namespace std;
 
const int maxn = 100009;
const int INF = 0x3F3F3F3F;
 
inline int read() {
char c = getchar();
int ret = 0;
for(; !isdigit(c); c = getchar());
for(; isdigit(c); c = getchar()) ret = ret * 10 + c - '0';
return ret;
}
 
struct edge {
int to;
edge* next;
} E[1000009], *pt = E, *head[maxn];
 
void addedge(int u, int v) {
pt->to = v; pt->next = head[u]; head[u] = pt++;
}
 
int N, scc[maxn], dfn[maxn], low[maxn], tot[maxn], CK = 0, n = -1, MOD;
stack<int> S;
set<pair<int, int> > bst;
 
void tarjan(int x) {
dfn[x] = low[x] = ++CK;
S.push(x);
for(edge* e = head[x]; e; e = e->next)
if(!dfn[e->to])
tarjan(e->to), low[x] = min(low[e->to], low[x]);
else if(!~scc[e->to])
low[x] = min(low[x], dfn[e->to]);
if(dfn[x] == low[x]) {
int t; n++;
do {
t = S.top(); S.pop();
tot[n]++;
scc[t] = n;
} while(t != x);
}
}
 
namespace DP {
edge E[1000009], *pt = E, *head[maxn];
int dp[maxn], cnt[maxn];
bool vis[maxn];
void addedge(int u, int v) {
pt->to = v; pt->next = head[u]; head[u] = pt++;
}
void init() {
memset(dp, 0, sizeof dp);
memset(cnt, 0, sizeof cnt);
memset(vis, 0, sizeof vis);
}
void Dp(int x) {
if(vis[x]) return;
vis[x] = true;
for(edge* e = head[x]; e; e = e->next) {
Dp(e->to);
if(dp[e->to] > dp[x])
dp[x] = dp[e->to], cnt[x] = cnt[e->to];
else if(dp[e->to] == dp[x] && (cnt[x] += cnt[e->to]) >= MOD) 
cnt[x] -= MOD;
}
dp[x] += tot[x];
if(!cnt[x]) cnt[x] = 1;
}
void work() {
for(int i = 0; i <= n; i++) 
if(!vis[i]) Dp(i);
int ans = 0, ans0 = 0;
for(int i = 0; i <= n; i++)
if(dp[i] > ans) ans = dp[i], ans0 = cnt[i];
else if(ans == dp[i] && (ans0 += cnt[i]) >= MOD) ans0 -= MOD;
printf("%d\n%d\n", ans, ans0);
}
}
 
void AddEdge() {
for(int x = 0; x < N; x++)
for(edge* e = head[x]; e; e = e->next) 
if(scc[x] != scc[e->to] && bst.find(make_pair(scc[x], scc[e->to])) == bst.end()) {
DP::addedge(scc[x], scc[e->to]);
bst.insert(make_pair(scc[x], scc[e->to]));
}
}
 
void TARJAN() {
memset(dfn, 0, sizeof dfn);
memset(low, 0, sizeof low);
memset(scc, -1, sizeof scc);
memset(tot, 0, sizeof tot);
for(int i = 0; i < N; i++) if(!dfn[i]) tarjan(i);
}
 
void init() {
N = read();
int m = read();
MOD = read();
while(m--) {
int u = read() - 1, v = read() - 1;
addedge(u, v);
}
DP::init();
}
 
int main() {
init();
TARJAN();
DP::init();
AddEdge();
DP::work();
return 0;
}

-------------------------------------------------------------------------------------------

1093: [ZJOI2007]最大半连通子图

Time Limit: 30 Sec  Memory Limit: 162 MB
Submit: 2105  Solved: 841
[Submit][Status][Discuss]

Description

Input

第一行包含两个整数N,M,X。N,M分别表示图G的点数与边数,X的意义如上文所述。接下来M行,每行两个正整数a, b,表示一条有向边(a, b)。图中的每个点将编号为1,2,3…N,保证输入中同一个(a,b)不会出现两次。

Output

应包含两行,第一行包含一个整数K。第二行包含整数C Mod X.

Sample Input

6 6 20070603
1 2
2 1
1 3
2 4
5 6
6 4

Sample Output

3
3

HINT

对于100%的数据, N ≤100000, M ≤1000000;对于100%的数据, X ≤10^8。

Source

BZOJ 1093: [ZJOI2007]最大半连通子图( tarjan + dp )的更多相关文章

  1. BZOJ 1093 [ZJOI2007]最大半连通子图 - Tarjan 缩点

    Description 定义一个半联通图为 : 对任意的两个点$u, v$,都有存在一条路径从$u$到$v$, 或从$v$到$u$. 给出一个有向图, 要求出节点最多的半联通子图,  并求出方案数. ...

  2. BZOJ 1093 [ZJOI2007] 最大半连通子图(强联通缩点+DP)

    题目大意 题目是图片形式的,就简要说下题意算了 一个有向图 G=(V, E) 称为半连通的(Semi-Connected),如果满足图中任意两点 u v,存在一条从 u 到 v 的路径或者从 v 到 ...

  3. BZOJ 1093 [ZJOI2007]最大半连通子图

    1093: [ZJOI2007]最大半连通子图 Time Limit: 30 Sec  Memory Limit: 162 MBSubmit: 1986  Solved: 802[Submit][St ...

  4. bzoj 1093 [ZJOI2007]最大半连通子图(scc+DP)

    1093: [ZJOI2007]最大半连通子图 Time Limit: 30 Sec  Memory Limit: 162 MBSubmit: 2286  Solved: 897[Submit][St ...

  5. Luogu P2272 [ZJOI2007]最大半连通子图(Tarjan+dp)

    P2272 [ZJOI2007]最大半连通子图 题意 题目描述 一个有向图\(G=(V,E)\)称为半连通的\((Semi-Connected)\),如果满足:\(\forall u,v\in V\) ...

  6. 【刷题】BZOJ 1093 [ZJOI2007]最大半连通子图

    Description 一个有向图G=(V,E)称为半连通的(Semi-Connected),如果满足:?u,v∈V,满足u→v或v→u,即对于图中任意 两点u,v,存在一条u到v的有向路径或者从v到 ...

  7. BZOJ1093: [ZJOI2007]最大半连通子图(tarjan dp)

    题意 一个有向图G=(V,E)称为半连通的(Semi-Connected),如果满足:?u,v∈V,满足u→v或v→u,即对于图中任意两点u,v,存在一条u到v的有向路径或者从v到u的有向路径.若G' ...

  8. P2272 [ZJOI2007]最大半连通子图 tarjan+DP

    思路:$tarjan+DP$ 提交:1次 题解:首先对于一个强连通分量一定是一个半连通分量,并且形成的半连通分量的大小一定是它的$size$,所以我们先缩点. 这样,我们相当于要在新的$DAG$上找一 ...

  9. bzoj 1093: [ZJOI2007]最大半连通子图【tarjan+拓扑排序+dp】

    先tarjan缩成DAG,然后答案就变成了最长链,dp的同时计数即可 就是题面太唬人了,没反应过来 #include<iostream> #include<cstdio> #i ...

随机推荐

  1. Oracle "Job定时"

    今天需要做个定时器,定时到别的库导入数据用到了Job,第一次使用记录下来,如果有第一次操作的可以借鉴一下 1.首先,使用Toad新建job,进入配置页面

  2. Android 开发笔记“Application 理解”

    Android 中Application类用法 1.             Application和Activity,Service一样是Android框架的一个系统组件,当Android程序启动时 ...

  3. [LeetCode]题解(python):129-Sum Root to Leaf Numbers

    题目来源: https://leetcode.com/problems/sum-root-to-leaf-numbers/ 题意分析: 一棵树,从跟节点到叶子节点比如1->2那么这个叶子代表12 ...

  4. [LeetCode]题解(python):075-Sort Colors

    题目来源: https://leetcode.com/problems/sort-colors/ 题意分析: 给定n个颜色,红色,白色和蓝色.分别用0,1,2代替,将这些颜色排序,0在1前,1在2前. ...

  5. Java 多线程 socket 取款例子 runnable callable

    socket部分参考 http://blog.csdn.net/kongxx/article/details/7259465 取款部分参考 http://blog.csdn.net/dayday198 ...

  6. C++ 面向对象学习2 构造方法

    Date.h #ifndef DATE_H #define DATE_H class Date{ public: Date(,,);//自定义了构造方法 会覆盖掉默认的无参构造方法 void setD ...

  7. Understanding and Selecting a SIEM/LM: Correlation and Alerting

    Continuing our discussion of core SIEM and Log Management technology, we now move into event correla ...

  8. C++模板:二分查找

    bool find(int x,int l,int r){ if(l>r)return false; int mid=(l+r)/2; if(s[mid]==x) return true; el ...

  9. SRM 585

    250 : 递推,从左下角到右下角走一条,剩下的都是子结构 const int mod = 1000000007; long long dp[1000010] , s[1000010]; class ...

  10. 高性能网站优化-创建快速响应的Web

    <高性能网站建设进阶指南> 优化原则 优化的目的是希望降低程序的整体开销. 减少开销 通常认为开销就是程序的执行时间.而在进行优化工作时,应该把重点放在对程序开销影响最大的那部分. 假设我 ...