离散课前来水篇题解
本题大意是说:给你一个长度为 n n n的序列 { d } {d} {d}你需要构造一个有向带权图,使得点 1 1 1到点 i i i的最短路长度为 d i d_i di同时使得所有边的边权之和尽可能地小。图中不能出现负环和重边。
思路:思维题
题目要求不出现负环和重边,但没说不可以出现负权边,因此显然答案必定小于等于0
我们按照最短路长度将
d
i
d_i
di按升序排序,
显然对于
i
i
i到
i
+
1
i+1
i+1肯定有一条正权边满足
d
i
+
1
−
d
i
d_{i+1}-d_i
di+1−di,于此同时我们可以给
i
+
1
i+1
i+1到
i
i
i添一条是这条正权边相反数的负权边
由此推广下来想,对于每个
j
j
j和
i
i
i,
j
>
i
j>i
j>i,我们都可以添一条等于
d
j
−
d
i
d_j-d_i
dj−di的相反数的负权边
预处理每相邻两点间的正权值
c
[
i
]
=
d
[
i
]
−
d
[
i
−
1
]
c[i]=d[i]-d[i-1]
c[i]=d[i]−d[i−1],那么每相邻两点间的这条负权边出现次数为
(
n
−
i
+
1
)
∗
(
i
−
1
)
(n-i+1)*(i-1)
(n−i+1)∗(i−1)
因此
a
n
s
=
d
n
−
∑
i
=
1
n
c
[
i
]
∗
(
n
−
i
+
1
)
∗
(
i
−
1
)
ans=d_n-\sum_{i=1}^nc[i]*(n-i+1)*(i-1)
ans=dn−∑i=1nc[i]∗(n−i+1)∗(i−1)
不画图应该看得懂吧(
放代码:
#include <bits/stdc++.h>
using namespace std;
const int N=1e5+10;
typedef long long ll;
int n,t,d[N],c[N];
int main(){
cin>>t;
while(t--){
cin>>n;
for(int i=1;i<=n;i++)cin>>d[i];
sort(d+1,d+1+n);
ll ans=d[n];
for(int i=2;i<=n;i++) c[i]=d[i]-d[i-1];
for(int i=1;i<=n;i++)
ans=ans-(ll)c[i]*(n-i+1)*(i-1);
cout<<ans<<endl;
}
return 0;
}