给定
n
n
n 个城市,编号从
1
1
1 到
n
n
n,第 i 个城市的美丽值为
a
i
a_i
ai,一个销售员想从城市
1
1
1 出发,经过其他城市至少一次且仅一次,最后返回城市
1
1
1,对于两个城市
i
,
j
(
i
≠
j
)
i,j (i ≠ j)
i,j(i=j),从
i
i
i 到
j
j
j 花费的费用为
max
(
c
i
,
a
j
−
a
i
)
\max(c_i, a_j - a_i)
max(ci,aj−ai),找到完成整个过程的最小费用。
1
≤
n
≤
1
0
5
,
0
≤
a
i
,
c
i
≤
1
0
9
1 ≤ n ≤ 10^5,0 ≤ a_i, c_i ≤ 10^9
1≤n≤105,0≤ai,ci≤109
思路:
由于每个城市都要经过一次,那么式子可以重写为:
max
(
c
i
,
a
j
−
a
i
)
\max(c_i, a_j - a_i)
max(ci,aj−ai) ->
c
i
+
max
(
0
,
a
j
−
a
i
−
c
i
)
c_i + \max(0, a_j - a_i - c_i)
ci+max(0,aj−ai−ci),因此我们可以先求出
∑
i
=
1
n
c
i
\sum\limits_{i=1}^{n}c_i
i=1∑nci,然后每条边的花费就变为
max
(
0
,
a
j
−
a
i
−
c
i
)
\max(0, a_j - a_i - c_i)
max(0,aj−ai−ci)。
根据式子
max
(
c
i
,
a
j
−
a
i
)
\max(c_i, a_j - a_i)
max(ci,aj−ai) 我们可知,从美丽值大的城市去往美丽值小的城市花费为 0,因此我们可以想到先将 a 排序,然后找到一条从
a
1
a_1
a1 到
a
n
a_n
an 的道路,然后剩下的道路的的花费就可以为 0 了。
根据“一步分为两步”更优的原则,我们要尽量经过更多的城市,若
a
i
>
a
j
+
c
j
a_i > a_j + c_j
ai>aj+cj
(
j
<
i
)
(j < i)
(j<i) ,则我们就要经过该城市 i ,到达城市 i 那一步最小花费为
a
i
−
max
j
<
i
(
a
j
+
c
j
)
a_i-\max\limits_{j<i}(a_j+c_j)
ai−j<imax(aj+cj),这个最小花费就是经过城市 i 产生的贡献, 且此时“
max
j
≤
i
(
a
j
+
c
j
)
\max\limits_{j ≤ i}(a_j + c_j)
j≤imax(aj+cj)”将会被更新为
a
i
+
c
i
a_i + c_i
ai+ci,就这样重复这个过程,直到到达
a
n
a_n
an,总的贡献为
∑
i
=
2
n
max
(
0
,
a
i
−
max
j
<
i
(
a
j
+
c
j
)
)
\sum_{i=2}^n \max(0, a_i-\max\limits_{j<i}(a_j+c_j))
∑i=2nmax(0,ai−j<imax(aj+cj))。
AC Code:
#include<bits/stdc++.h>usingnamespace std;typedeflonglong ll;intmain(){
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);int n;
cin >> n;
vector<int>a(n),c(n);
ll ans =0;for(int i =0; i < n; i++){
cin >> a[i]>> c[i];
ans += c[i];}
vector<int>p(n);iota(p.begin(), p.end(),0);sort(p.begin(), p.end(),[&](int i,int j){return a[i]< a[j];});int mx = a[p[0]]+ c[p[0]];for(int i =1; i < n; i++){
ans +=max(0, a[p[i]]- mx);
mx =max(mx, a[p[i]]+ c[p[i]]);}
cout << ans <<'\n';return0;}