ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

[IOI2016]shortcut 题解

2021-02-07 10:33:37  阅读:317  来源: 互联网

标签:qq r1 题解 ll IOI2016 shortcut leq mn1 l1


洛谷地址//UOJ地址

题意描述

在一个 \(n\) 个点的链上,每个点下面挂了一条长度为 \(d_i\) 的边
现在可以添加一条边连接两个链上的点,这条边长度为 \(c\),现在要使直径最小

题解

\(IOI\) 题目被 \(wc\) 老师五分钟带过……
首先求出每个点到第一个点的距离,设其为 \(L\),那么每两点间的最短路就是 \(L_j-L_i+d_i+d_j\)
若在 \(a,b\) 两点间添加一条边,那么 \(i,j\) 间的距离就变成 \(|L_i-L_a|+|L_j-L_b|+d_i+d_j\)
那么这个时候我们想找到 \(min(式1,式2)\) 的最大值
这个时候想到了二分一个 \(M\),然后去验证这个 \(M\)是否可行
对于加边前,两点距离就已经小于等于 \(M\) 的,我们就没必要管他,重点是 \(L_j-L_i+d_i+d_j>M\) 的
然后我们看一下式二,既然式一不能满足限制,那么式二肯定要满足限制,也就是 \(|L_i-L_a|+|L_j-L_b|+d_i+d_j \leq M\)
然后就考虑爆拆绝对值,分别求最小值再求交
然后老师就默认大家都会,没有讲了
其实呢,老师的意思是,把绝对值爆拆之后,把含 \(a,b\) 的项移到右边去,构成约束,找到最紧的约束,这样就可以判
于是我们来拆开这个式子看一下(分类中的小于等于和大于等于就省略掉等于了)

  • \(L_j>L_b\)且\(L_i>L_a\)

\[L_i-L_a+L_j-L_b+d_i+d_j \leq M \]

\[L_i+L_j+d_i+d_j-M \leq L_a+L_b \]

  • \(L_j>L_b\)且\(L_i<L_a\)

\[L_a-L_i+L_j-L_b+d_i+d_j \leq M \]

\[L_j-L_i+d_i+d_j-M \leq L_b-L_a \]

\[L_i-L_j-d_i-d_j+M \geq L_a-L_b \]

  • \(L_j<L_b且L_i>L_a\)

\[L_i-L_a+L_b-L_j+d_i+d_j \leq M \]

\[L_i-L_j+d_i+d_j-M \leq L_a-L_b \]

  • \(L_j<L_b且L_i<L_a\)

\[L_a-L_i+L_b-L_j+d_i+d_j \leq M \]

\[-L_i-L_j+d_i+d_j-M \leq -L_a-L_b \]

\[L_i+L_j-d_i-d_j+M \geq L_a+L_b \]


啊,\(mk\) 排版有待提升
然后我们得到了一系列约束,这个时候我们发现很多符号不太统一,所以我们给第二、四种情况两边取负,这样的话 \(L_a\) 就一直会是正的(然后我们会从求最大值变成求最小值)
我们对于四种情况,把左式求出,考虑枚举一个 \(j\),我们可以想到用一个线段树来找到 \(L_i+d_i\) 或 \(L_i-d_i\) ,似乎需要两棵树(没试过)
这样的话时间就是 \(O(nlog_nlog_n)\),还是过不去,我们还需要更好的
原课件是证明了一个单调性之后使用双指针,但是我并没有看懂,于是在网上找到了一位大佬的代码做参考,使用单调队列
然后由于我比较菜,一眼看过去并不怀疑其正确性,所以没有研究为什么单调队列就可以了
然后我们说一下怎么判断有没有解
我们的 \(L\) 数组肯定是单调不降的,这没问题,但是细心的小伙伴可能发现,有没有可能,第一种情况下,约束是最紧的,但是我们在该约束条件下找到的\(a,b\)并不满足该约束的前提(也就是 \(L_j>L_b\)且\(L_i>L_a\) )
这是不可能的,因为如果不符合前提,那么爆拆绝对值之后的值就是负数,不是最优的
最后,枚举一个 \(a\),用两组 \(l,r\) 分别代表两组约束,然后如果 \(r1>=l1且r1>=l2\),\(r2\)同理,成立,那么就是有解了
具体细节可以看代码(这次没有放毒瘤码风了)

#include<iostream>
#include<cstdio>
#include<cstring>
#define ll long long
using namespace std;
const ll inf=((1ll<<62)-1);
ll n,m,s[10100101],d[1010001],L,R,ans,mid;

bool check(ll sam){
	ll mx1=-inf,mx2=-inf,mn1=inf,mn2=inf,Mx=-inf,mx=d[1]-s[1];
	ll qq[1001001],l1=n+1,r1=n,l2=1,r2=0,l=1,r=1;
	qq[1]=1;
	for(ll i=2;i<=n;++i){
		if(mx+s[i]+d[i]>sam){
			mn1=min(mn1,sam-d[i]+s[i]-mx-m);
			mn2=min(mn2,sam-d[i]-s[i]-mx-m);
			while(l<=r&&d[qq[l]]-s[qq[l]]+d[i]+s[i]>sam){
				Mx=max(Mx,d[qq[l]]+s[qq[l]]);
				++l;
			}
			mx1=max(mx1,-sam+d[i]+s[i]+Mx+m);
			mx2=max(mx2,-sam+d[i]-s[i]+Mx+m);
		}
		mx=max(mx,d[i]-s[i]);
		while(r>=l&&d[i]-s[i]-d[qq[r]]+s[qq[r]]>=0)--r;
		qq[++r]=i;
	}
	if(mx1>mn1||mx2>mn2)return 0;
	for(ll i=1;i<=n;++i){//寻找 a b 
		while(l1>1&&s[l1-1]+s[i]>=mx1)--l1;
		while(r1>=l1&&s[r1]+s[i]>mn1)--r1;
		while(r2<n&&s[r2+1]-s[i]<=-mx2)++r2;
		while(l2<=r2&&s[l2]-s[i]<-mn2)++l2;
		if(l1>r1||l2>r2)continue;
		if(!(l2>r1||l1>r2))return 1;
	}
	return 0;
}

int main(){
	scanf("%lld%lld",&n,&m);
	for(ll i=2;i<=n;++i)scanf("%lld",&s[i]);
	for(ll i=1;i<=n;++i)s[i]+=s[i-1];
	for(ll i=1;i<=n;++i)scanf("%lld",&d[i]);
	L=0,R=(n+1)*(1e9);
	while(L<=R){
		mid=(L+R)>>1;
		if(check(mid))ans=mid,R=mid-1;
		else L=mid+1;
	}
	cout<<ans;
}

标签:qq,r1,题解,ll,IOI2016,shortcut,leq,mn1,l1
来源: https://www.cnblogs.com/caijiLYC/p/14384106.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有