题意和思路看这篇博客就行了:https://www.cnblogs.com/cjyyb/p/10507937.html

有个问题需要注意:对于每个scc,只需要考虑进入这个scc的时间即可,其实和从哪个点进没有关系,因为scc内每个点都可以互相到达,所以只需记录时间就囊括了所有的情况,比如时间3从1号点进和时间4从2号点进是等价的,这也是为什么可以随便选择一颗生成树的原因。对于scc的出边,边的长度是val[u] + val[v] - 1,因为假设从scc x的根 到点scc y的点v,时间是val[u] + 1,而scc y的根到v的距离是val[v],所以要求原装态需要减去这个。当然,这个边需要对两个scc的gcd的gcd取模,以判断从这条边到下一条边可以到达的状态。

代码:

#include <bits/stdc++.h>
using namespace std;
const int maxn = 100010; int head[maxn], Next[maxn * 2], ver[maxn * 2], tot;
int heade[maxn], Nexte[maxn * 2 * 50], edgee[maxn * 2 * 50], vere[maxn * 2 * 50], tote, cnt;
int n, m, D, GCD, g[maxn], f[maxn][51], pre[maxn][51], deg[maxn], val[maxn], c[maxn];
int dfn[maxn], low[maxn], num, top, Stack[maxn];
char v[maxn][51];
bool vis[maxn], ins[maxn];
vector<int> scc[maxn];
void add(int x, int y) {
ver[++tot] = y;Next[tot] = head[x];head[x] = tot;
} void adde(int x, int y, int z) {
vere[++tote] = y, edgee[tote] = z, Nexte[tote] = heade[x], heade[x] = tote, deg[y]++;
} void solve(int x, int p) {
val[x] = p, vis[x] = 1;
for (int i = head[x]; i; i = Next[i]) {
int y = ver[i];
if(c[y] != cnt) continue;
if(!vis[y]) solve(y, p + 1);
else GCD = __gcd(GCD, abs(p + 1 - val[y]));
}
} void tarjan(int x) {
dfn[x] = low[x] = ++num;
Stack[++top] = x, ins[x] = 1;
for (int i = head[x]; i; i = Next[i]) {
if (!dfn[ver[i]]) {
tarjan(ver[i]);
low[x] = min(low[x], low[ver[i]]);
} else if (ins[ver[i]])
low[x] = min(low[x], dfn[ver[i]]);
}
if (dfn[x] == low[x]) {
cnt++;
int y;
do {
y = Stack[top--], ins[y] = 0;
c[y] = cnt, scc[cnt].push_back(y);
} while(x != y);
GCD = D, solve(x, 0); g[cnt] = GCD;
for (int i = 0; i < GCD; i++)
for (int j = 0; j < scc[cnt].size(); j++) {
for (int k = i; k < D; k += GCD)
if(v[scc[cnt][j]][k] == '1') {
v[scc[cnt][j]][i] = '1';
break;
}
}
for (int i = 0; i < GCD; i++)
for (int j = 0; j < scc[cnt].size(); j++) {
if(v[scc[cnt][j]][(val[scc[cnt][j]] + i) % GCD] == '1')
pre[cnt][i]++;
}
}
} void dp(void) {
int ans = 0;
memset(f, -0x3f, sizeof(f));
f[c[1]][0] = pre[c[1]][0];
queue<int> q;
for (int i = 1; i <= cnt; i++) {
if (!deg[i])
q.push(i);
}
while(!q.empty()) {
int x = q.front();
q.pop();
for (int i = heade[x]; i; i = Nexte[i]) {
int y = vere[i];
deg[y]--;
if(deg[y] == 0)
q.push(y);
}
for (int i = heade[x]; i; i = Nexte[i]) {
for (int j = 0; j < D; j++) {
int y = vere[i], z = edgee[i];
f[y][(z + j) % D] = max(f[y][(z + j) % D], f[x][j] + pre[y][(z + j) % g[y]]);
}
}
for (int i = 0; i < D; i++)
ans = max(ans, f[x][i]);
}
printf("%d\n", ans);
} int main() {
int x, y;
scanf("%d%d%d", &n, &m, &D);
for (int i = 1; i <= m; i++) {
scanf("%d%d", &x, &y);
add(x, y);
}
for (int i = 1; i <= n; i++)
scanf("%s", v[i]);
for (int i = 1; i <= n; i++) {
if(!dfn[i])
tarjan(i);
}
for (int j = 1; j <= n; j++)
for (int i = head[j]; i; i = Next[i]) {
int y = ver[i];
if(c[j] == c[y]) continue;
int dd = __gcd(g[c[j]], g[c[y]]);
int d = (val[j] - val[y] + 1 + D) % D;
for (int k = d % dd; k < D; k += dd) {
adde(c[j], c[y], k);
}
}
dp();
}

  

Codeforces 1137C Museums Tour (强连通分量, DP)的更多相关文章

  1. The Largest Clique UVA - 11324( 强连通分量 + dp最长路)

    这题  我刚开始想的是  缩点后  求出入度和出度为0 的点  然后统计个数  用总个数 减去 然而 这样是不可以的  画个图就明白了... 如果  减去度为0的点  那么最后如果出现这样的情况是不可 ...

  2. UVa 11324 The Largest Clique (强连通分量+DP)

    题意:给定一个有向图,求一个最大的结点集,使得任意两个结点,要么 u 能到 v,要么 v 到u. 析:首先,如果是同一个连通分量,那么要么全选,要么全不选,然后我们就可以先把强连通分量先求出来,然后缩 ...

  3. CF1137C Museums Tour(tarjan+DP)

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

  4. 【Codeforces 1137C】Museums Tour

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

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

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

  6. UVA 11324 The Largest Clique(强连通分量+缩点DAG的DP)

    题意:给定一个有向图,求出一个最大的结点集,这个节点集中的随意两个点之间至少一个能到达还有一个点. 思路:假设一个点在这个节点集中,那么它所在的强连通分量中的点一定所有在这个节点集中,反之亦然, 求出 ...

  7. Codeforces Round #244 (Div. 2) C. Checkposts (tarjan 强连通分量)

    题目:http://codeforces.com/problemset/problem/427/C 题意:给你n座城市,m条有向道路,然后有一个机制,你在某一个城市设置检查点,那么被设置的检查点受保护 ...

  8. uva11324 有向图的强连通分量+记忆化dp

    给一张有向图G, 求一个结点数最大的结点集,使得该结点集中任意两个结点u和v满足,要么u可以到达v, 要么v可以到达u(u和v相互可达也可以). 因为整张图可能存在环路,所以不好使用dp直接做,先采用 ...

  9. BZOJ 1179 Atm(强连通分量缩点+DP)

    题目说可以通过一条边多次,且点权是非负的,所以如果走到图中的一个强连通分量,那么一定可以拿完这个强连通分量上的money. 所以缩点已经很明显了.缩完点之后图就是一个DAG,对于DAG可以用DP来求出 ...

随机推荐

  1. linux服务器版svn安装

    1.检查svn是否安装:rpm -aq subversion2.安装命令yum -y install subversion3.建立svn版本库数据存储根目录mkdir -p /application/ ...

  2. Java_脚本引擎_03_nashorn支持es6

    一.前言 jdk1.8的nashorn 支持部分es6语法. 二.支持es6 jdk默认是关闭了对es6的支持的,想要开启对es6的支持,需要设置一下jvm参数: -Dnashorn.args=--l ...

  3. CATransform3D 矩阵变换之立方体旋转实现细节 (转)

    原文地址 http://blog.csdn.net/ch_soft/article/details/7351896 第一部分.前几天做动画,使用到了CATransform3D ,由于没有学过计算机图形 ...

  4. SQL-主键与外键

    1.PRIMARY KEY 主键,唯一标识一行或多行,不允许重复值,也不允许未NULL. 语法:[CONSTRAINT <约束名>] PRIMARY KEY [(列名1,列名2...)] ...

  5. Tomcat 优化方案 和 配置详解

    转载: http://blog.csdn.net/yi2672379417/article/details/51442229

  6. EF各版本增删查改及执行Sql语句

    自从我开始使用Visual Studio 也已经经历了好几个版本了,而且这中间EF等框架的改变也算是比较多的.本篇文章记录下各个版本EF执行Sql语句和直接进行增删查改操作的区别,方便自己随时切换版本 ...

  7. 关于yii的日志路由组件的配置问题

    最近突然意识到日志是很好滴debug工具,所以研究了一下yii的日志配置,想想应该还会有像我这样的小白不懂这些问题的,就分享一下了.有错误烦请大神们指出config/main.php 中配置,这个想必 ...

  8. 四、Jmeter--参数化

    一.CSV 参数化 1.我们做性能测试需要并发多个用户,为了真实模拟用户行为,我们需要模拟多个不同的用户登录,这是我们就需要进行参数化.这里我们选择比较常用的参数化方法-CSV Data Set Co ...

  9. WPF案例:如何设计历史记录查看UI

    (CSDN博客目前不支持外链, 只能纯文字) 设计WPF的UI,一般遵循下面的步骤: 1.首先分析数据结构 2.根据数据结构选择合理控件 3.定制外观 具体对于历史记录查看UI, 我们可以得知: 1. ...

  10. webrtc自带client的音频引擎创建代码走读

    src\webrtc\examples\peerconnection\client\conductor.cc1.bool Conductor::InitializePeerConnection()1. ...