[CF1504E]Travelling Salesman Problem

Travelling Salesman Problem

题解

我们可以考虑将原式转化一下,记 p 1 , . . . , p i , . . . , p n , p n + 1 = p 1 p_{1},...,p_{i},...,p_{n},p_{n+1}=p_{1} p1,...,pi,...,pn,pn+1=p1为所走的顺序,由于是一个环,从哪里开始并不重要。
由于每个点都必定会被经过一次,可以先将 c i c_{i} ci减去,答案为 ∑ i = 1 n c i + max ⁡ ( a p i + 1 − a p i − c i , 0 ) \sum_{i=1}^{n}c_{i}+\max(a_{p_{i+1}}-a_{p_{i}}-c_{i},0) i=1nci+max(api+1apici,0)
前面的是一个定值,我们目的是让后面的总和最小。
我们先按 a i a_{i} ai大小排个序,由于从 a i a_{i} ai较小的走向 a i a_{i} ai较大的,后面那块一定是0,所以必定有一种最优做法是,从最大的走到最小的,再从最小的往回走。

我们考虑如何用最小的代价从最大走到最小。
我们可以考虑将 a i a_{i} ai转化为一条 a i + c i − − > a i a_{i}+c_{i}-->a_{i} ai+ci>ai的线段,很明显,当且仅当,线段之间有空隙时,这段空隙才需要被算入答案。
所以,答案即为 ∑ i = 2 n max ⁡ ( 0 , a i − m a x j < i ( a j + c j ) ) + ∑ i = 1 n c i \sum_{i=2}^{n}\max(0,a_{i}-max_{j<i}(a_{j}+c_{j}))+\sum_{i=1}^{n}c_{i} i=2nmax(0,aimaxj<i(aj+cj))+i=1nci

时间复杂度 O ( n l o g   n ) O\left(nlog\,n\right) O(nlogn)

源码

#include<bits/stdc++.h>
using namespace std;
#define MAXN 100005
#define lowbit(x) (x&-x)
#define reg register
#define mp make_pair
#define fir first
#define sec second
typedef long long LL;
typedef unsigned long long uLL;
typedef unsigned int uint;
const int INF=0x7f7f7f7f;
const int jzm=233;
const int mo=998244353;
const double Pi=acos(-1.0);
typedef pair<int,int> pii;
const double PI=acos(-1.0);
template<typename _T>
_T Fabs(_T x){return x<0?-x:x;}
template<typename _T>
void read(_T &x){
	_T f=1;x=0;char s=getchar();
	while(s>'9'||s<'0'){if(s=='-')f=-1;s=getchar();}
	while('0'<=s&&s<='9'){x=(x<<3)+(x<<1)+(s^48);s=getchar();}
	x*=f;
}
int n;LL ans;
struct ming{int a,c;}b[MAXN];
bool cmp(ming x,ming y){return x.a<y.a;}
int main(){
	read(n);for(int i=1;i<=n;i++)read(b[i].a),read(b[i].c),ans+=b[i].c;
	sort(b+1,b+n+1,cmp);int maxx=b[1].a+b[1].c;
	for(int i=2;i<=n;i++){
		if(maxx<b[i].a)ans+=1ll*(b[i].a-maxx);
		maxx=max(maxx,b[i].a+b[i].c);
	}
	printf("%lld\n",ans);
	return 0;
}

谢谢!!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值