牛客网暑期ACM多校训练营(第十场)F.Rikka with Line Graph

牛客网暑期ACM多校训练营(第十场)F.Rikka with Line Graph


做法:\(G'\) 中的对应原图两条边(a,b) (c,d)的最短路为:
\[ w[a][b] + w[c][d] + 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;
}

猜你喜欢

转载自www.cnblogs.com/RRRR-wys/p/9849423.html