「JSOI2015」地铁线路
「JSOI2015」地铁线路
第一问很简单:对于每条线路建一个点,然后所有该条线路覆盖的点向它连边,权值为 \(1\) ,然后它向所有线路上的点连边,权值为 \(0\) 。
然后,跑一边最短路就可以求出第一问了。
接下来考虑第二问。
我们在最短路图上面跑 \(\text{DP}\) 我们把所有线路按照 \(dis\) 排序,然后用距离为 \(dis - 1\) 的线路来更新。
我们发现如果一条最短路为 \(d\) 的线路上出现了一个最短路为 \(d\) 的点,那么显然我们不会在这里上车,可能在这里下车。
暴力的搞法就是暴力枚举,每次 \(O(n^2)\) 的转移 :\(dp_i \leftarrow dp_j + dis(i, j),dis_i = dis_j + 1\)
但我们发现一条线路是一条链,所以我们只需要每次记一下前缀和后缀的最大值然后再择优,这样就可以 \(O(n)\) 转移了。
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <vector>
#include <string>
#include <deque>
#include <map>
#define rg register
#define file(x) freopen(x".in", "r", stdin), freopen(x".out", "w", stdout)
using namespace std;
template < class T > inline void read(T& s) {
s = 0; int f = 0; char c = getchar();
while ('0' > c || c > '9') f |= c == '-', c = getchar();
while ('0' <= c && c <= '9') s = s * 10 + c - 48, c = getchar();
s = f ? -s : s;
}
const int _ = 5e5 + 5, __ = 2e6 + 5;
int tot, head[_]; struct Edge { int v, w, nxt; } edge[__ << 1];
inline void Add_edge(int u, int v, int w) { edge[++tot] = (Edge) { v, w, head[u] }, head[u] = tot; }
int n, m, s, t, node, dis[_], dp[_], p[_], pre[_], suf[_];
inline bool cmp(const int& i, const int& j) { return dis[i + n] < dis[j + n]; }
string str;
vector < int > vec[_];
map < string, int > mp;
deque < int > Q;
inline void Dijkstra() {
memset(dis, -1, sizeof dis), dis[s] = 0;
Q.push_back(s);
while (!Q.empty()) {
int u = Q.front(); Q.pop_front();
for (rg int i = head[u]; i; i = edge[i].nxt) {
int v = edge[i].v, w = edge[i].w;
if (~dis[v]) continue ;
if (w) dis[v] = dis[u] + w, Q.push_back(v);
else dis[v] = dis[u], Q.push_front(v);
}
}
}
inline void calc() {
for (rg int i = 1; i <= m; ++i) p[i] = i;
sort(p + 1, p + m + 1, cmp);
int l, r = 0;
while (r < m && dis[p[r + 1] + n] <= 0) ++r;
for (rg int d = 1; d <= m; ++d) {
l = r + 1;
while (r < m && dis[p[r + 1] + n] == d) ++r;
for (rg int j = l; j <= r; ++j) {
int u = p[j], len = vec[u].size() - 1;
for (rg int k = 0; k <= len + 1; ++k) pre[k] = suf[k] = -2e9;
for (rg int k = 1; k <= len; ++k) {
int v = vec[u][k];
if (dis[v] == d - 1) pre[k] = suf[k] = dp[v];
}
for (rg int k = 1; k <= len; ++k) pre[k] = max(pre[k], pre[k - 1] + 1);
for (rg int k = len; k >= 1; --k) suf[k] = max(suf[k], suf[k + 1] + 1);
for (rg int k = 1; k <= len; ++k) {
int v = vec[u][k];
if (dis[v] == d) dp[v] = max(dp[v], max(pre[k], suf[k]));
}
}
}
}
int main() {
#ifndef ONLINE_JUDGE
file("cpp");
#endif
read(m), read(n);
for (rg int i = 1; i <= n; ++i) cin >> str, mp[str] = ++node;
for (rg int x, i = 1; i <= m; ++i) {
read(x), vec[i].push_back(0);
while (x--) {
cin >> str, vec[i].push_back(mp[str]);
Add_edge(mp[str], i + n, 1), Add_edge(i + n, mp[str], 0);
}
}
cin >> str, s = mp[str];
cin >> str, t = mp[str];
Dijkstra(), calc();
printf("%d\n%d\n", dis[t], dp[t]);
return 0;
}
「JSOI2015」地铁线路的更多相关文章
- 「JSOI2015」串分割
「JSOI2015」串分割 传送门 首先我们会有一个贪心的想法:分得越均匀越好,因为长的绝对比短的大. 那么对于最均匀的情况,也就是 \(k | n\) 的情况,我们肯定是通过枚举第一次分割的位置,然 ...
- 「JSOI2015」isomorphism
「JSOI2015」isomorphism 传送门 我们还是考虑树哈希来判同构. 但是我们需要使用一些特殊的手段来特殊对待假节点. 由于是无向树,我们首先求出重心,然后以重心为根跑树哈希. 此处我们不 ...
- 「JSOI2015」symmetry
「JSOI2015」symmetry 传送门 我们先考虑构造出原正方形经过 \(4\) 种轴对称变换以及 \(2\) 种旋转变换之后的正方形都构造出来,然后对所得的 \(7\) 个正方形都跑一遍二维哈 ...
- 「JSOI2015」染色问题
「JSOI2015」染色问题 传送门 虽然不是第一反应,不过还是想到了要容斥. 题意转化:需要求满足 \(N + M + C\) 个条件的方案数. 然后我们就枚举三个数 \(i, j, k\) ,表示 ...
- 「JSOI2015」圈地
「JSOI2015」圈地 传送门 显然是最小割. 首先对于所有房子,权值 \(> 0\) 的连边 \(s \to i\) ,权值 \(< 0\) 的连边 \(i \to t\) ,然后对于 ...
- 「JSOI2015」最小表示
「JSOI2015」最小表示 传送门 很显然的一个结论:一条边 \(u \to v\) 能够被删去,当且仅当至少存在一条其它的路径从 \(u\) 通向 \(v\) . 所以我们就建出正反两张图,对每个 ...
- 「JSOI2015」套娃
「JSOI2015」套娃 传送门 考虑贪心. 首先我们假设所有的套娃都互相不套. 然后我们考虑合并两个套娃 \(i\),\(j\) 假设我们把 \(i\) 套到 \(j\) 里面去,那么就可以减少 \ ...
- 「JSOI2015」非诚勿扰
「JSOI2015」非诚勿扰 传送门 我们首先考虑一名女性选中她列表里第 \(x\) 名男性的概率(假设她列表里共有 \(s\) 名男性): \[ P = p \times (1 - p) ^ {x ...
- 「JSOI2015」salesman
「JSOI2015」salesman 传送门 显然我们为了使收益最大化就直接从子树中选大的就好了. 到达次数的限制就是限制了可以选的子树的数量,因为每次回溯上来都会减一次到达次数. 多种方案的判断就是 ...
随机推荐
- c++踩坑大法好 赋值和指针的区别
1,先说结论: 两个指针指向同一个结构,一个改了结构,另一个也会改掉. 两个指针指向同一个结构,修改了其中一个的指向,并且改了其中的内容,另一个不为所动. 2,看例子 main.cpp #includ ...
- 模块二、shell脚本逻辑结构
七.if结构条件句知识与实践 (一)if条件句单双分支语法 1.单分支 if 条件 then 指令 fi 2.双分支 if 条件 then 指令 else 指令集2 fi (二)if条件句多分支语句 ...
- 《Mongo权威指南》学习手记
1.ObjectId: 是“_id”的默认类型.mongo没有用自增主键原因:多个服务器同步自动增加主键值费时费力. mongo初衷是作分布式数据库,所以能在分片环境中生成唯一的标示符非常重要. Ob ...
- Linux下基于PAM机制的USB Key的制作
摘自:https://server.zzidc.com/fwqpz/157.html USB Key这个概念最早是由加密锁厂家提出来的,加密锁是用来防止软件盗版的硬件产品,加密锁的概念是使安装在计算机 ...
- 跨表更新,Mysql Update Join
背景 项目新导入了一批人员数据,这些人的有的部门名称发生了变化,有的联系方式发生了变化,暂且称该表为t_dept_members, 系统中有另外一张表 t_user_info 记录了人员信息. 要求将 ...
- hadoop cdh 的那些坑 第二弹
卧槽 ....一直连不上datanode 不知道为什么数据节点一直连接不上.. 2019-07-19 16:10:00,156 INFO org.apache.hadoop.ipc.Client: R ...
- 阻止click点击事件
遇到一个屏蔽点击事件,以前一般都是通过js控制,阻止事件,今天看到css加一个样式就能屏蔽,来记录一下 //css禁用鼠标点击事件 .test { pointer-events: none; } 随便 ...
- 进程管理 supervisor
背景知识: supervisor是用Python开发的一套通用的进程管理程序,能将一个普通的命令行进程变为后台daemon,并监控进程状态,异常退出时能自动重启. 它是通过fork/exec的方式把这 ...
- 题解【洛谷P3951】[NOIP2017]小凯的疑惑
题目描述 小凯手中有两种面值的金币,两种面值均为正整数且彼此互素.每种金币小凯都有 无数个.在不找零的情况下,仅凭这两种金币,有些物品他是无法准确支付的.现在小 凯想知道在无法准确支付的物品中,最贵的 ...
- 发送数据给sap和接收
1.确保已经连通sap 2.发送数据:这是以表的形式发送,而且是批量发送给sap 3.接收sap返回信息:这个比较特别,碰到时试一试 package com.yiyezhiqiu.lyh.utils; ...