题解 [51nod1340]地铁环线
题解 [51nod1340]地铁环线
题面
解析
一开始看到只有120行就打算写一写,
结果一刚就是三个星期摆摆摆
本来是当查分约束入门学的.
step 1
首先来考虑下如果已知总长度\(s\)如何判断是否合法.
显然差分约束
对于\(dis(x,y)>=w\)
这个式子等价于\(dis[x]+w<=dis[y]\),
即\(dis[y]+(-w)>=dis[x]\).
因此,
若\(x<y\),则\(y\)向\(x\)连一条边权为\(-w\)的边.
若\(x>y\),则\(y\)向\(x\)连一条边权为\(s-w\)的边(要绕一圈,yy一下就知道了).
对于\(dis(x,y)<=w\)
这个式子就是\(dis[x]+w>=dis[y]\).
- 若\(x<y\),则\(x\)向\(y\)连一条边权为\(w\)的边.
- 若\(x>y\),则\(x\)向\(y\)连一条边权为\(s+w\)的边.
又因为边权至少为\(1\),即\(dis[x]+1<=dis[y]\).
\(dis[y]+(-1)>=dis[x]\).
因此\(i+1\)要向\(i\)连一条边权为\(-1\)的边(n-1要特判)
最后,跑n-1边Bellman_Ford,
若还能进行松弛操作,即存在边\((x,y,w)\),使\(dis[x]+w<=dis[y]\),
则存在负环,就不合法.
step 2
差分约束还只是判断,
但我们要统计方案数啊.
注意到每个点的\(dis\)都是\(k*s+b\)的形式(\(k,b\)为常数).
因此,我们可以设\(dis[x][k]\)表示\(s\)前的系数为\(k\)时\(dis[x]\)只计算\(b\)的最小值.
那么\(dis[x]\)就等于\(\min(k*s+dis[x][k]).\)
然后,对于每一条边(x,y,w),我们都可以把\(s\)的值域化为若干段,
使每一段都是取一个\(k\)使\(s\)取这一段值时的\(dis\)值最小.
这个可以用单调栈维护.
那么我们维护两个单调栈,
一个是\(dis[x]+w\)的,一个是\(dis[y]\)的.
然后对于一段值域若\(dis[x]+w>dis[y]\)则合法.
对每条边都这么来一次,用前缀和+差分来统计这一段权值的合法边数.
若合法边数等于总边数,则这一段值域合法,统计答案.
code(代码中的inf不知道是什么情况希望dalao指点):
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#define ll long long
#define int ll
using namespace std;
inline int read(){
int sum=0,f=1;char c=getchar();
while(c>'9'||c<'0'){if(c=='-') f=-1;c=getchar();}
while(c<='9'&&c>='0'){sum=sum*10+c-'0';c=getchar();}
return f*sum;
}
const int N=55;
struct list{ll x,v;}lis[N*N*N<<1];
int T,n,m1,m2,cnt,tot;
ll dis[N][N*2],inf;
inline ll up(ll tb,ll tk){
if(tk<0) tk=-tk,tb=-tb;
ll tt=tb/tk;
return tt+(tt*tk<tb);
}/*向上取整*/
inline ll down(ll tb,ll tk){
if(tk<0) tk=-tk,tb=-tb;
ll tt=tb/tk;
return tt-(tt*tk>tb);
}/*向下取整*/
struct line{
ll l,r,k,b;
inline ll f(int x){return k*x+b;}
}s1[N*N*N<<1],s2[N*N*N<<1];
inline void push(line *a,int &num,line t){
while(num&&a[num].f(a[num].l)>=t.f(a[num].l)) num--;
if(num) t.l=down(-(t.b-a[num].b),t.k-a[num].k)+1,a[num].r=t.l-1;
a[++num]=t;
}
inline void put(ll l,ll r){
lis[++tot]=(list){l,1};
lis[++tot]=(list){r+1,-1};
}
inline void check(line s1,line s2){
ll l=max(s1.l,s2.l),r=min(s1.r,s2.r);
if(l>r) return ;
line t=(line){0,0,s1.k-s2.k,s1.b-s2.b};
if(t.f(l)<0&&t.f(r)<0) return ;
put(t.f(l)>=0? l:up(-t.b,t.k),t.f(r)>=0? r:down(-t.b,t.k));
}
struct edge{
ll x,y,w,k;
inline void bf(){
for(int i=0;i<=(n<<1);i++)
if(i+k>=0&&i+k<=(n<<1)) dis[y][i+k]=min(dis[y][i+k],dis[x][i]+w);
}
inline void clac(){
int n1=0,n2=0;
for(int i=(n<<1);i>=0;i--){
if(dis[x][i]<(inf>>1)) push(s1,n1,(line){n,inf,i+k-n,dis[x][i]+w});
if(dis[y][i]<(inf>>1)) push(s2,n2,(line){n,inf,i-n,dis[y][i]});
}
for(int k1=1,k2=1;k1<=n1&&k2<=n2;s1[k1].r<=s2[k2].r? k1++:k2++)
check(s1[k1],s2[k2]);
}
}e[N<<2];
inline void add(ll x,ll y,ll w,ll k){
e[++cnt]=(edge){x,y,w,k};
}
inline bool cmp(list a,list b){return a.x<b.x;}
signed main(){
T=read();
while(T--){
n=read(),m1=read(),m2=read();
memset(dis,1,sizeof(dis));
memset(lis,0,sizeof(lis));
inf=dis[0][0];dis[0][n]=0;
cnt=tot=0;
for(int i=0;i<n;i++) add((i+1)%n,i,-1,i==n-1);
for(int i=1;i<=m1;i++){
int x=read(),y=read(),w=read();
add(y,x,-w,(x>y));
}
for(int i=1;i<=m2;i++){
int x=read(),y=read(),w=read();
add(x,y,w,-(x>y));
}
for(int i=1;i<n;i++)
for(int j=1;j<=cnt;j++) e[j].bf();
for(int i=1;i<=cnt;i++) e[i].clac();
ll sum=0,ans=0;
lis[++tot]=(list){inf,0};
sort(lis+1,lis+tot+1,cmp);
for(int i=1;i<tot;i++){
ans+=((sum+=lis[i].v)==cnt)*(lis[i+1].x-lis[i].x);
}
printf("%lld\n",ans<inf>>1? ans:-1);
}
return 0;
}
题解 [51nod1340]地铁环线的更多相关文章
- 51nod1340 地铁环线
http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1340 设x为环线的长度,要判断某个特定的x是否可行,不难将题目转为差分约 ...
- 51nod1340地铁环线
经典题. 经典差分约束模型. 但是 显然这个总长是有上下界的. 直接二分总长,判断有没有负环 如果没有负环好办,有负环就不知道怎么偏了. 因为没有单调性! (如果所有没有单调性的函数图像,都知道往哪里 ...
- [题解] 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各有一条边.定义 ...
- 【51nod】1340 地铁环线
今天头非常疼,躲在家里没去机房 反正都要颓废了,然后花了一上午研究了一下这道神题怎么做-- 题解 首先我们发现,如果我们设\(dis[i]\)为从\(0\)节点走到\(i\)节点的距离 那么题目中给出 ...
- CCF-CSP题解 201703-4 地铁修建
求1-n最长边最小的路径. 最短路变形.dis值向后延申的方式是:\[dis[j]=min(dis[j],max(dis[i],w(i,j))\] 显然满足dijkstra贪心的选择方式.spfa也当 ...
- 【UR #2】跳蚤公路
[UR #2]跳蚤公路 参照yjc方法.也就是地铁环线那个题. 求每个点不在负环内的x的取值范围.然后所有1到j能到i的j的范围取交.得到答案. 每个边形如kx+b的直线,每个环也是 每个点不在负环内 ...
- buaacoding_2018算法期末上机G题.地铁建设题解
// 标注:本文旨在为博主确立一种题解的基本范式,以避免博主的题解流于AC代码的粘贴.此基本范式为:完整而简洁明了的思路及其推导说明,力图触及问题的本质并衍生对同类问题的思路分析,使得题解具有泛用性, ...
- 【luogu P4005 清华集训2017】小Y和地铁
题目描述 小 Y 是一个爱好旅行的 OIer.一天,她来到了一个新的城市.由于不熟悉那里的交通系统,她选择了坐地铁. 她发现每条地铁线路可以看成平面上的一条曲线,不同线路的交点处一定会设有 换乘站 . ...
随机推荐
- SpringBoot中service注入失败(A component required a bean of type 'XXService' that could not found)
先写了JUnit,发现启动不了,注释掉有问题的service也不可以.可能是因为spring开始时会加载所有service吧. 按照网友们的说法,一般需要检查: 1.入口类有没有写MapperScan ...
- Mybatis笔记1
Mybatis 持久层框架,数据访问层 mybatis是一个优秀的基于java的持久层框架,它内部封装了jdbc,使开发者只需要关注sql语句本身,而不需要花费精力去处理加载驱动,创建连接,创建sta ...
- 【工具】导入导出 Excel
文章目录 前言 当前支持的功能 方法api 配置 如何使用(Demo) 实现思路(该工具类可正确的一个大前提) 后记 前言 之前写的项目中,有个需求,需要导出导入Excel表格: 本来很简单的一件事, ...
- Python调用API接口的几种方式
Python调用API接口的几种方式 相信做过自动化运维的同学都用过API接口来完成某些动作.API是一套成熟系统所必需的接口,可以被其他系统或脚本来调用,这也是自动化运维的必修课. 本文主要介绍py ...
- 1.关于Python,你可能不知道的
启示录 写在前面———— 至于python有多牛逼,这里不介绍了,安装也不说了,网上一堆一堆的安装教程. 本文只介绍需要知道的 常识知识———— 1.python 发音:英 [ˈpaɪθən] 美 [ ...
- Scala 面向对象编程之类
定义一个简单的类 // 定义类,包含field以及方法 class HelloWorld { private var name = "leo" def sayHello() { p ...
- DNS 解析
DNS即为Domain Name System的缩写形式,就是所谓的域名系统,它是互联网的一项服务.它作为将域名和IP地址相互映射的一个分布式数据库,能够使人更方便地访问互联网. 如果想访问某个网站( ...
- 安装CentOS7服务器
1. 基本安装 https://www.cnblogs.com/kreo/p/4396825.html 2.安装补充 防火墙 / FTP / Nginx https://www.cnblogs.com ...
- js-Array数组
一.创建数组的两种方式 1.使用Array构造函数 var colors = new Array(); var colors = new Array(20); var colors = new Arr ...
- jQuery笔试题汇总整理
1 你在公司是怎么用jquery的? 答:在项目中是怎么用的是看看你有没有项目经验(根据自己的实际情况来回答) 你用过的选择器啊,动画啊,表单啊,ajax事件等 配置Jquery环境 下载jquery ...