題意
給你一個數組\(d\),\(d[i]\)表示從節點\(1\)到其他各個節點的最短路的長度,然后你可以對這個圖進行加邊(可以是負邊),但不允許存在一個權值和為負數的回路。
題解
按樣例的思想,大概就是將這些點按距離\(1\)的距離從小到大排個序,這樣就使得所有點連成一條直線,這樣總是可以保證加最多的負邊,然后就開始加負邊,對於每個點,將他和他前面的點全連上,這樣就可以保證加足夠多的負邊且沒有負環。
然后就是計算,很簡單的一個推公式,很容易知道,相鄰的兩個是互相抵消的,不需要計算,設\(S_i\)表示節點\(i\)到節點\(1\)的距離(排序后),則
\[ans=\sum_{i=1}^n\sum_{j=i+2}^n(S_j-S_i) \]
硬算的話肯定時間超了,於是對\(S_i\)和\(S_j\)分開計算,對於\(S_i\),它總共被計算了\(n-i-1\)次,最多計算到\(S_{n-2}\)。對於\(S_j\),它總共被計算了\(j-2\)次,從\(S_3\)開始計算,於是上式又可以寫為
\[ans=\sum_{i=1}^{n-2}(n-i-1)(S_{n-i+1}-S_i) \]
AC代碼
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <iomanip>
#include <cstdio>
#include <vector>
#include <cmath>
#include <stack>
#include <cstring>
#include <map>
#include <set>
#define IO ios::sync_with_stdio(NULL)
#define sc(z) scanf("%d", &(z))
#define _ff(i, a, b) for (ll i = a; i <= b; ++i)
#define _rr(i, a, b) for (ll i = b; i >= a; --i)
#define _f(i, a, b) for (ll i = a; i < b; ++i)
#define _r(i, a, b) for (ll i = b - 1; i >= a; --i)
#define mkp make_pair
#define endl "\n"
#define lowbit(x) x&(-x)
using namespace std;
typedef long long ll;
typedef long double ld;
const int N = 1e5 + 5;
const ll mod = 1e9 + 7;
const ld EPS = 1e-8;
ll d[N];
int main() {
IO;
int T; cin >> T;
while (T--) {
ll n; cin >> n;
_ff(i, 1, n) cin >> d[i];
sort(d + 1, d + 1 + n);
ll ans = 0;
_ff(i, 1, n - 2) {
ans += (n - i - 1) * (d[n - i + 1] - d[i]);
}
// ans -= d[n];
if (ans) cout << "-";
cout << ans << endl;
}
return 0;
}