【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.一天,她来到了一个新的城市.由于不熟悉那里的交通系统,她选择了坐地铁. 她发现每条地铁线路可以看成平面上的一条曲线,不同线路的交点处一定会设有 换乘站 . ...
随机推荐
- 「Python」10个python项目
1. Pillow. Pillow是由Alex Clark以及其他贡献者实现的“友好版”的PIL.PIL即Python Imaging Library,作者是Fredrik Lundh及其他开发者.A ...
- kendalltau肯德尔和谐系数
sklearn实战-乳腺癌细胞数据挖掘(博客主亲自录制视频教程) https://study.163.com/course/introduction.htm?courseId=1005269003&a ...
- OpenCV---圆检测
推文:Opencv2.4.9源码分析——HoughCircles 霍夫圆检测 加载一幅图像并对其模糊化以降噪 对模糊化后的图像执行霍夫圆变换 . 在窗体中显示检测到的圆. def detect_cir ...
- 目前最快速的多线程Kmeans算法,java实现
目前最快速Kmeans算法,并由java实现!面对很大的K值表现依然很好. 代码地址: https://github.com/Jethu1/fastKmeans #1.这是一个由java实现的的,多线 ...
- Unicode/UTF-8/GBK/ASCII 编码简介
转载:http://blog.csdn.net/u014785687/article/details/73928167 一.字符编码简介 1.ASCII编码 每一个ASCII码与一个8位(bit)二进 ...
- Nodejs文件监控chokidar
最近有个需求是扫描用例,用例是放在svn上,如果每次扫描都去遍历目录的话会有占用太多的io,所以想着用文件监控,有文件变化时只对该文件进行操作. Nodejs里的 chokidar 模块可以更好的对文 ...
- 巧用Javascript将相对路径地址转换为绝对路径
这里介绍的其实本质上是两种方法,通过创建DOM或通过JavaScript计算: 1)通过新创建的Image, 经测试会发送一个Aborted的请求,并且IE6不支持, 将new Image改成docu ...
- 【BZOJ】4596: [Shoi2016]黑暗前的幻想乡
[题意]给定n个点的无向完全图,有n-1个公司各自分管一部分路,要求所有公司都有修路的生成树数.n<=17. [算法]容斥原理+生成树计数(矩阵树定理) [题解]每个生成树方案是一个公司有无修路 ...
- phpcms模板
cms的样式有很多种,我们学习的是phpcms,这些cms都是大同小异,学会了一种就可以使用其它的cms. PHPCMS是一款网站管理软件.该软件采用模块化开发,支持多种分类方式,使用它可方便实现个性 ...
- Spring Boot中使用Spring-data-jpa让数据访问更简单、更优雅
在上一篇Spring中使用JdbcTemplate访问数据库中介绍了一种基本的数据访问方式,结合构建RESTful API和使用Thymeleaf模板引擎渲染Web视图的内容就已经可以完成App服务端 ...