link

\(\text{Description:}\)

一个国家有 \(n\) 个城市,\(m\) 条有向道路组成。在这个国家一个星期有 \(d\) 天,每个城市有一个博物馆。

有个旅行团在城市 \(1\) 出发,当天是星期一。每天早上,如果这个城市的博物馆开了,那么可以去这个博物馆参观。每天晚上,旅行团可以选择沿一条出边前往下一个城市,或者结束旅行。一个城市可以经过多次。

请问旅行团最多能参观多少个博物馆。一个博物馆参观了多次,只计算一次。

\(1\le n, m\le 10^5,1\le d\le 50\)

\({\rm Solution:}\)

由于\({\rm d}\)只有\({\rm 50}\)天,所以考虑分层图,分成\({\rm 50}\)层,每个点只有在它开放的那个时间(那一层)有\({\rm 1}\)的权值,其余权值均为\({\rm 0}\),对于原图的一条边 \({\rm E(x, y)}\), 在分层图中 \({\rm E(x_i, y_{i+1}), (1\le i\le d-1)}\) 且 \({\rm E(x_d, y_1)}\)。

然后缩点成\({\rm DAG}\), \({\rm DP}\) 即可。

注意一个细节就是如果很多个点 \({\rm x_i}\) 在同一个强连通分量中,权值只加一次。

#include <vector>
#include <set>
#include <stack>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <assert.h>
#include <algorithm> using namespace std; #define LL long long
#define debug(...) fprintf(stderr, __VA_ARGS__)
#define GO debug("GO\n")
#define rep(i, a, b) for (register int (i) = (a); (i) <= (b); ++ (i)) const int INF = 0x3f3f3f3f;
const char Enter = '\n';
inline int rint() {
register int x = 0, f = 1; register char c;
while (!isdigit(c = getchar())) if (c == '-') f = -1;
while (x = (x << 1) + (x << 3) + (c ^ 48), isdigit(c = getchar()));
return x * f;
}
struct Stream {
Stream operator>> (int &x)
{ x = rint(); return *this; }
Stream operator<< (int x)
{ printf("%d", x); return *this; }
Stream operator<< (char ch)
{ putchar(ch); return *this; }
} xin, xout; template<typename T> inline void chkmin(T &a, T b) { a > b ? a = b : 0; }
template<typename T> inline void chkmax(T &a, T b) { a < b ? a = b : 0; } const int N = 1e5 + 10; struct Edge {
int v, nxt;
} E[N * 51];
int tot, head[N * 51];
vector<int> G[N * 51]; inline void add(int u, int v)
{ E[++tot] = (Edge){v, head[u]}; head[u] = tot; } int n, m, d, val[N * 50], col[N * 50], dfn[N * 50], low[N * 50], have[N * 50]; stack<int> stk;
void tarjan(int u) {
dfn[u] = low[u] = ++dfn[0];
stk.push(u);
for (register int i = head[u]; i; i = E[i].nxt) {
int v = E[i].v;
if (!dfn[v]) tarjan(v), chkmin(low[u], low[v]);
else if (!col[v]) chkmin(low[u], dfn[v]);
}
if (dfn[u] == low[u]) {
col[0]++;
int v;
do {
v = stk.top(); stk.pop();
col[v] = col[0];
} while (v != u);
}
} int dp[N * 50]; int DFS(int u) {
if (dp[u]) return dp[u];
for (int i = 0; i < G[u].size(); ++ i) {
int v = G[u][i];
chkmax(dp[u], DFS(v));
}
return dp[u] += val[u];
} int main() {
xin >> n >> m >> d;// fast_read
int u, v;
rep(i, 1, m) {
xin >> u >> v;
rep(j, 1, d - 1) add(u + (j - 1) * n, v + j * n);
add(u + (d - 1) * n, v);
}
rep(i, 1, d * n) if (!dfn[i]) tarjan(i); rep(i, 1, n * d) for (register int j = head[i]; j; j = E[j].nxt) if (col[E[j].v] != col[i])
G[col[i]].push_back(col[E[j].v]); rep(i, 1, n) {
static char str[N]; scanf("%s", str + 1);
rep(j, 1, d) {
if (str[j] == '1' and have[col[i + (j - 1) * n]] != i)
have[col[i + (j - 1) * n]] = i, val[col[i + (j - 1) * n]]++;
}
} xout << DFS(col[1]) << Enter; return 0;
}

[CF1137]Museums Tour的更多相关文章

  1. CF1137 C. Museums Tour

    CF1137 C. Museums Tour 一般来说的正常思路:看到有向图的第一思路都是缩点(但是要分析一波证明强联通分量中的个体可以拼凑成整体,一般都是边和点可以经过无数次然后贡献只算一次这种类型 ...

  2. CF 1138 E. Museums Tour

    E. Museums Tour 链接 分析: 按时间建出分层图,每个点形如(u,t),表示u在在t个时刻的点,tarjan缩点.每个强连通分量中的点都能经过,然后DAG上dp. 代码: #includ ...

  3. CF1137C Museums Tour(Tarjan,强连通分量)

    好题,神题. 题目链接:CF原网 洛谷 题目大意: 一个国家有 $n$ 个城市,$m$ 条有向道路组成.在这个国家一个星期有 $d$ 天,每个城市有一个博物馆. 有个旅行团在城市 $1$ 出发,当天是 ...

  4. 【Codeforces 1137C】Museums Tour

    Codeforces 1137 C 题意:给一个有向图,一周有\(d\)天,每一个点在每一周的某些时刻会开放,现在可以在这个图上从\(1\)号点开始随意地走,问最多能走到多少个开放的点.一个点如果重复 ...

  5. CF1137C Museums Tour

    思路 强连通分量的好题 对于每个博物馆,因为时间的限制条件,不好直接统计, 发现d很小,可以建出d层分层图,原图<u,v>的边变成<u,i>到<v,i+1>的边,& ...

  6. Codeforces 1137C Museums Tour (强连通分量, DP)

    题意和思路看这篇博客就行了:https://www.cnblogs.com/cjyyb/p/10507937.html 有个问题需要注意:对于每个scc,只需要考虑进入这个scc的时间即可,其实和从哪 ...

  7. 【CF1137C】 Museums Tour 拆点+缩点

    https://codeforc.es/contest/1137/problem/C # 题意 给你n个点,每个点有k天博物馆开放时间的安排表. 有m条单向道路,走过一条边需要一个晚上,经过后就是第二 ...

  8. CF1137C Museums Tour(tarjan+DP)

    由于d很小,所以可以把每个点拆成d个点,然后对于边(x,y),连边时连接((x,i),(y,i+1))及((x,d),(y,1)).然后可以对这样连的边跑一遍tarjan缩点.然后直接暴力DP即可.不 ...

  9. codeforces选做

    收录了最近本人完成的一部分codeforces习题,不定期更新 codeforces 1132E Knapsack 注意到如果只使用某一种物品,那么这八种物品可以达到的最小相同重量为\(840\) 故 ...

随机推荐

  1. canvas转img,blob相互转换

    摘自:https://www.cnblogs.com/jyuf/p/7251591.html 函数都比较简单,直接看就ok了 /*----------------------------------- ...

  2. Qt绘制动态曲线

    首先*.pro文件中加一句 QT += charts 然后 mainwindow.cpp文件如下: #include "mainwindow.h" #include "u ...

  3. jQuery实现页面回到顶部功能

    <!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title&g ...

  4. e.currentTarget与e.target

    e.currentTarget指的是注册了事件监听器的对象,而e.target指的是该对象里的子对象   html中 <div id="addBtn" v-on:click= ...

  5. JQuery传值,接收PrintWriter的int接收不了

    <servlet>中的代码 <JSP中的代码> 很苦恼,我想要,<servlet>中传入的(0),在<jsp>中接收到这个参数,然后进行判断,从而达到判 ...

  6. javascript node节点学习

    node节点学习 1 . 获取节点(元素)的方法 document.getElementById(); document.getElementsByTagName() document.getElem ...

  7. 嵌入式C语言自我修养 04:Linux 内核第一宏:container_of

    4.1 typeof 关键字 ANSI C 定义了 sizeof 关键字,用来获取一个变量或数据类型在内存中所占的存储字节数.GNU C 扩展了一个关键字 typeof,用来获取一个变量或表达式的类型 ...

  8. PTA(BasicLevel)-1008数组元素循环右移问题

    一 .问题描述      原题描述 将长度为n的整形数组A进行右移m位操作, [A0 A1 A2 A3 ... Am...An-1]变为[An-m...An-1 A0 A1 A2 A3 ...An-m ...

  9. 20155224 2016-2017-2 《Java程序设计》第4周学习总结

    20155224 2016-2017-2 <Java程序设计>第4周学习总结 教材学习内容总结 第六章 第六章主要学习了子类与父类的继承. 先定义一个程序,另一程序可继承他 如: publ ...

  10. 20155230 《Java程序设计》实验一(Java开发环境的熟悉) 实验报告

    练习题: 凯撒密码: import java.util.Scanner; import java.io.*; public class exp1 { public static void main(S ...