牛客网暑期ACM多校训练营(第十场)F.Rikka with Line Graph
做法:\(G'\) 中的对应原图两条边(a,b) (c,d)的最短路为:
\[ w[a][b] + w[c][d] + 2* min(dis[a][c], dis[a][d], dis[b][c], dis[b][d])\]
其中\(dis[i][j]\)表示原图G中i 到 j 的最短路。
那么就要求 $\sum_{a=1}^n \sum_{b=a+1}^n \sum_{c=1}^n \sum_{d=c+1}^n min(dis[a][c], dis[a][d], dis[b][c], dis[b][d]) $,可以枚举a,b ,求出 \(A[i] = min(dis[a][i], dis[b][i])\),式子就转化为:
\[ \sum_{a=1}^n \sum_{b=a+1}^n min(A_a, A_b) \]
这个可以通过归并排序,同时求解,也可以先将A排序然后扫一遍。另外本题需要大力卡常。。。我的归并写法tle了,之后换成sort,加上快读才过。
#include <bits/stdc++.h>
#define pb push_back
typedef long long ll;
const ll mod = 998244353;
inline int read() {
char c = getchar(); int x = 0, f = 1;
while(!isdigit(c)) {if(c=='-') f = -1; c=getchar();}
while(isdigit(c)) {x = x * 10 + c-'0'; c=getchar();}
return x*f;
}
using namespace std;
int T, n;
ll d[502][503], ans, A[503];
int main() {
T = read();
while(T--) {
n = read(); ans = 0;
for(int i = 1; i <= n; ++i)
for(int j = 1; j <= n; ++j) {
d[i][j] = read();
if(i < j) ans += d[i][j];
}
ans %= mod;
ans *= (1LL*n*(n-1)/2 - 1LL);
ans %= mod;
for(int k = 1; k <= n; ++k)
for(int i = 1; i <= n; ++i) if(i!=k)
for(int j = 1; j <= n; ++j) if(i!=j&&j!=k) {
if(d[i][j] > d[i][k] + d[k][j]) d[i][j] = d[i][k]+d[k][j];
}
for(int a = 1; a <= n; ++a)
for(int b = a+1; b <= n; ++b) {
for(int i = 1; i <= n; ++i) A[i] = min(d[a][i], d[b][i]);
sort(A+1,A+1+n);
for(int i = 1; i <= n; ++i) ans+=1LL*(n-i)*A[i]%mod;
ans %= mod;
}
printf("%lld\n",ans);
}
return 0;
}