【51nod】1340 地铁环线
今天头非常疼,躲在家里没去机房
反正都要颓废了,然后花了一上午研究了一下这道神题怎么做……
题解
首先我们发现,如果我们设\(dis[i]\)为从\(0\)节点走到\(i\)节点的距离
那么题目中给出的所有关系都变成了\(n\)个变量中两两的大小关系式
这像什么,差分约束哇(听说这是noip知识点?可我noip的时候根本没听过哇qwq)
可是在列关系式的时候,你发现对于\(a -> b\)当(b < a)的时候,我们还需要一个值,就是环的总长,正好是我们需要统计的东西……
我们先看看关系式怎么列,设环的总长为\(x\)
对于边长至少大于1的话,可以把它当成第一种限制
我们对于\((a,b) >= d\)当\(a < b\)的时候
\(dis[b] - dis[a] >= d\)我们换成\(<=\)号就是\(dis[a] - dis[b] <= -d\)连一条\((b,a) = -d\)
当\(a > b\)
\(dis[b] + x - dis[a] >= d\)我们换成\(<=\)号就是\(dis[a] - dis[b] <= x - d\)连一条\((b,a) = x-d\)
对于\((a,b) <= d\)当\(a < b\)的时候
\(dis[b] - dis[a] <= d\)连一条\((a,b) = d\)
对于\((a,b) <= d\)当\(a > b\)的时候
\(dis[b] + x - dis[a] <= d\)连一条\((a,b) = -x + d\)
这里,如果我们把x换成特定的值,我们只要检查一下整张图有没有负环,用Bellman-ford,就可以判断这个x合不合法
当然啦,这个算法肯定跑不过去的,我们再来看一下我们建出的图
如果我们把x当成变量,我们会发现我们每一条边都是一个一次函数,我们设\(dis[s][k]\)是从\(0\)点走到\(s\)点,一次函数的一次项系数是\(k\)
\(dis[s][k]\)是里存的是一次函数\(kx + b\)里最小的那个\(b\)(因为最短路我们总要尽量少啊)
那么,我们可以用这些一次函数拼起来,我们这个点在整个x值域上的最小值!只要维护一个栈,斜率从大到小往里面加直线,栈里面的直线同时记录一下这条直线控制着哪段区间上的最小值就可以
再把每条边取出来,我们发现我们的关系式是
\(dis(u,k) + e(u,v) >= dis(v,k)\)
也就是,我们需要知道\(dis(u,k) + e(u,v)\)在整个值域上的函数(也就是无数个分段一次函数拼出的最小值,它长成了一个上凸包),和\(dis(v,k)\)在整个值域上的函数,我们要取这两个函数中,\(dis(u,k) + e(u,v)\)在\(dis(v,k)\)上面的部分,从前往后拿出直线来比较即可
最后我们对于每个边得到了很多区间,我们要求出所有边的区间交,可以把这些区间设置成左端点+1(右端点+1的位置)-1的差分,当一个区间的值是边的数量时,就把这段区间统计进答案
而对于解有无穷多的情况,我们设置值域是n到正无穷,如果我们的答案和正无穷很接近了,那么就是-1了
写到这,我不禁想到了一个往边权里填多项式的另一道题,叫BIKE,一看这个题目大概就知道是谁出的了。。
看来这还是一个比较神奇的技巧啊><
代码
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
//#define ivorysi
#define fi first
#define se second
#define mp make_pair
#define inf (1LL << 55)
#define space putchar(' ')
#define enter putchar('\n')
using namespace std;
typedef long long int64;
int N,M1,M2,tot,p1,p2;
int64 dis[55][105];
pair<int64,int> P[100005];
template<class T>
void read(T &res) {
res = 0;T f = 1;char c = getchar();
while(c < '0' || c > '9') {
if(c == '-') f = -1;
c = getchar();
}
while(c >= '0' && c <= '9') {
res = res * 10 + c - '0';
c = getchar();
}
res *= f;
}
template<class T>
void out(T x) {
if(x < 0) {x = -x;putchar('-');}
if(x >= 10) {
out(x / 10);
}
putchar('0' + x % 10);
}
struct Line {
int64 L,R,k,b;
int64 f(int64 x) {
return k * x + b;
}
}L1[10005],L2[10005];
int id;
void insert(int64 L,int64 R) {
P[++tot] = mp(L,1);
P[++tot] = mp(R + 1,-1);
}
int64 up(int64 A,int64 B) {
if(B < 0) B = -B,A = -A;
int64 C = A / B;
return C + (C * B < A);
}
int64 down(int64 A,int64 B) {
if(B < 0) B = -B,A = -A;
int64 C = A / B;
return C - (C * B > A);
}
void push(Line *a,int &len,Line t) {
while(len && t.f(a[len].L) <= a[len].f(a[len].L)) --len;
if(len) {
int64 B = -(a[len].b - t.b),K = (a[len].k - t.k);
t.L = down(B,K) + 1;
a[len].R = t.L - 1;
}
a[++len] = t;
}
void check(Line U,Line D) {
int64 L = max(U.L,D.L),R = min(U.R,D.R);
if(L > R) return;
Line t;t.k = U.k - D.k,t.b = U.b - D.b;
if(t.f(L) >= 0) {
if(t.f(R) >= 0) insert(L,R);
else insert(L,down(-t.b,t.k));
}
else if(t.f(R) >= 0) {insert(up(-t.b,t.k),R);}
}
struct node{
int s,t,k;int64 b;
void update() {
for(int i = 0 ; i <= 2 * N ; ++i) {
if(i + k >= 0 && i + k <= 2 * N) {
dis[t][i + k] = min(dis[s][i] + b,dis[t][i + k]);
}
}
}
void calc() {
p1 = 0,p2 = 0;
for(int i = N * 2 ; i >= 0 ; --i) {
if(dis[s][i] < inf / 2)
push(L1,p1,(Line){(int64)N,inf,(int64)(i - N + k),dis[s][i] + b});
if(dis[t][i] < inf / 2)
push(L2,p2,(Line){(int64)N,inf,(int64)(i - N),dis[t][i]});
}
int t1 = 1,t2 = 1;
for( ;t1 <= p1 && t2 <= p2 ;) {
check(L1[t1],L2[t2]);
if(L1[t1].R <= L2[t2].R) ++t1;
else ++t2;
}
}
}E[10005];
int sumE;
void Solve() {
read(N);read(M1);read(M2);
for(int i = 0 ; i <= N ; ++i) {
for(int j = 0 ; j <= 2 * N ; ++j) dis[i][j] = inf;
}
dis[0][N] = 0;
sumE = 0;
int s,t;int64 d;
for(int i = 0 ; i < N ; ++i) {
int s = i,t = (i + 1) % N;
E[++sumE] = (node){t,s,(t < s),-1};
}
for(int i = 1 ; i <= M1 ; ++i) {
read(s);read(t);read(d);
E[++sumE] = (node){t,s,(t < s),-d};
}
for(int i = 1 ; i <= M2 ; ++i) {
read(s);read(t);read(d);
E[++sumE] = (node){s,t,-(t < s),d};
}
for(int i = 1 ; i <= N ; ++i) {
for(int j = 1 ; j <= sumE ; ++j) {
E[j].update();
}
}
tot = 0;
for(int j = 1 ; j <= sumE ; ++j) id = j,E[j].calc();
P[++tot] = mp(inf + 1,0);
sort(P + 1,P + tot + 1);
s = 0;
int64 ans = 0;
for(int i = 1 ; i <= tot ; ++i) {
s += P[i].se;
if(s == sumE) {
ans += P[i + 1].fi - P[i].fi;
}
}
if(ans > (inf / 4)) ans = -1;
out(ans);enter;
}
int main() {
#ifdef ivorysi
freopen("f1.in","r",stdin);
#endif
int T;
read(T);
while(T--) {
Solve();
}
}
【51nod】1340 地铁环线的更多相关文章
- [题解] 51 nod 1340 地铁环线
不难看出这是一道差分约束的题目. 但是如果想按照通常的题目那样去建边的话,就会发现这句话--相邻两站的距离至少是1公里--建边后就直接让整个题出现了负环(默认是按求最短路建边),没法做了. 这时我们就 ...
- 【51nod 1340】地铁环线
题目 有一个地铁环线,环线中有N个站台,标号为0,1,2,...,N-1.这个环线是单行线,一共由N条有向边构成,即从0到1,1到2,..k到k+1,...,N-2到N-1,N-1到0各有一条边.定义 ...
- 题解 [51nod1340]地铁环线
题解 [51nod1340]地铁环线 题面 解析 本文参考这篇博客 一开始看到只有120行就打算写一写, 结果一刚就是三个星期摆摆摆 本来是当查分约束入门学的. step 1 首先来考虑下如果已知总长 ...
- 51nod1340 地铁环线
http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1340 设x为环线的长度,要判断某个特定的x是否可行,不难将题目转为差分约 ...
- 51nod 1340 差分约束
思路: 带未知量的Floyd 很强 http://yousiki.net/index.php/archives/87/ //By SiriusRen #include <bits/stdc++. ...
- 51nod1340地铁环线
经典题. 经典差分约束模型. 但是 显然这个总长是有上下界的. 直接二分总长,判断有没有负环 如果没有负环好办,有负环就不知道怎么偏了. 因为没有单调性! (如果所有没有单调性的函数图像,都知道往哪里 ...
- 【UR #2】跳蚤公路
[UR #2]跳蚤公路 参照yjc方法.也就是地铁环线那个题. 求每个点不在负环内的x的取值范围.然后所有1到j能到i的j的范围取交.得到答案. 每个边形如kx+b的直线,每个环也是 每个点不在负环内 ...
- 【luogu P4005 清华集训2017】小Y和地铁
题目描述 小 Y 是一个爱好旅行的 OIer.一天,她来到了一个新的城市.由于不熟悉那里的交通系统,她选择了坐地铁. 她发现每条地铁线路可以看成平面上的一条曲线,不同线路的交点处一定会设有 换乘站 . ...
- P4005 小 Y 和地铁
题目描述 小 Y 是一个爱好旅行的 OIer.一天,她来到了一个新的城市.由于不熟悉那里的交通系统,她选择了坐地铁. 她发现每条地铁线路可以看成平面上的一条曲线,不同线路的交点处一定会设有 换乘站 . ...
随机推荐
- [DeeplearningAI笔记]卷积神经网络4.6-4.10神经网络风格迁移
4.4特殊应用:人脸识别和神经网络风格转换 觉得有用的话,欢迎一起讨论相互学习~Follow Me 4.6什么是神经网络风格转换neural style transfer 将原图片作为内容图片Cont ...
- python---Celery分布式任务队列了解
linux下定时器了解 Celery 框架学习笔记(不错哟) Celery 分布式任务队列快速入门 Celery的最佳实践 一.Celery介绍 Celery 是一个 基于python开发的分布式异步 ...
- DHCP及DHCP多作用域服务器工作原理
一.DHCP服务是什么 DHCP称为动态主机配置协议.DHCP服务允许工作站连接到网络并且自动获取一个IP地址.配置DHCP服务的服务器可以为每一个网络客户提供一个IP地址.子网掩码.缺省网关.一个W ...
- CentOS下安装JDK1.8
0.卸载旧版本 键入命令java-version,查询当前JDK版本 如果版本号不是想要的,键入rpm -qa|grep gcj 键入命令 yum -y remove (后接查询得到的版本),移除老版 ...
- HDU 1299 基础数论 分解
给一个数n问有多少种x,y的组合使$\frac{1}{x}+\frac{1}{y}=\frac{1}{n},x<=y$满足,设y = k + n,代入得到$x = \frac{n^2}{k} + ...
- PHP提取链接批量下载
2014年年初的时候,曾经受委托完成一个视频网站,那时最大的技术障碍是一个大视频比如500MB,在一个带宽环境不怎么快的服务器(比如1Mbps)上提供播放的问题. 这里会遇到两种情况,第一种情况是客户 ...
- 登入时session的处理方式
暂时理解不够彻底 有空在详细介绍,先记录代码 1:创建一个工具类 存取当前登录用户 package com.liveyc.eloan.util; import javax.servlet.http ...
- 使用generatorConfig工具自动生成mybatis的实体类以及dao接口和映射文件
1:数据准备 创建一个数据库表 CREATE TABLE `logininfo` ( `id` ) NOT NULL AUTO_INCREMENT, `username` ) DEFAULT NULL ...
- 【Linux 命令】fping ping 包间隔时间详解
服务器间检查会用到fping的命令,期间遇到了一个问题,需要将ping包间的间隔时间设置为100毫秒,查看fping -h看下,找到了-i和-p两个参数: 看到这两个参数,我当时的表情是这样的: 看不 ...
- 黑色的企业网站后台管理模板html源码
链接:http://pan.baidu.com/s/1kUMqDU3 密码:83xt