原文链接https://www.cnblogs.com/zhouzhendong/p/NowCoder-2018-Summer-Round10-F.html

题目传送门 - https://www.nowcoder.com/acm/contest/148/F

题意

  给定一个完全图 $G$ ,有边权。

  定义其线图的一条边的权值为“该边连接的两个点,在原图中对应的边 的权值和”。

  在图 $L(G)$ 上,定义 $dis(i,j)$ 为节点 $i,j$ 之间的最短路。

  求 $\sum_{i=1}^{n}\sum_{j=i+1}^{n}dis(i,j)$ 。

  $n\leq 500,边权 \leq 10^9,{\rm Time\ Limit\ = \ 10s}$

题解

  线图很大,我们不大可能把它建出来,所以,我们首先考虑在 $L(G)$ 上,两个点的距离是什么。

  对于 $L(G)$ 上的一条路径,我们把它包含的点还原到原图 $G$ 上,可以得到原图上的一些边顺次连接得到的路径。容易发现,在计算 $dis$ 时,这条路径上,两端的边的权值被算了一次,中间的被算了两次。

  简单分析可得,两端的边的权值一定会被算一次。而中间的可以随便弄。

  记原图中,编号为 $i$ 的边的权值为 $w_i$ 。

  于是,计算 $dis(a,b) _{in\ L(G)} = w_a+w_b+2\times dis(x,y)_{in\ G}$

  这个 $x,y$ 分别指 把路径搞到原图上之后,除掉两端点,剩下的两个端点的节点编号。显然我们要让这个 $dis(x,y)_{in\ G}$ 最小。考虑到 $x$ 可以选择 $a$ 的任意一个端点,$y$ 可以选择 $b$ 的任意一个端点,所以我们可以 Floyd 预处理最短路,在这 $4$ 种情况下取最小值,来方便的计算线图上任意两个点的距离。

  考虑枚举线图上的一个点,即原图上的一条边 $(a,b)$ ,首先,两端的被算一次的边的贡献是好求的,我们考虑如何求被算两倍的那部分。考虑求出每一个点距离 $a,b$ 的最短路的最小值,后面称为“距离”,我们需要得到另一条边。对于原图上的每一个点,我们强制可以和他配对的点的距离比他大(相等的情况先搁着),这样,我们只要对于每一个点,知道有多少个点的距离比他大就好了。显然我们可以对于每一个点的距离大小排个序,就可以很方便的算出来了,而且有距离相等的情况也可以搞定了。

  但是这样的复杂度是 $O(n^3\log n)$ 的,显然不能通过。

  我们考虑把排序的那一只 $log$ 省掉。只需要预处理每一个节点到其他节点的距离,并从小到大排列,然后我们要得到两个点的,归并一下就好了。

  这样,Floyd 是 $O(n^3)$ 的;枚举一条边是 $O(n^2)$ 的,得到边后的处理是 $O(n)$ 的,所以总复杂度也是 $O(n^3)$ 的。

  最终时间复杂度 $O(n^3)$ 。

代码

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N=505,mod=998244353;
int read(){
int x=0;
char ch=getchar();
while (!isdigit(ch))
ch=getchar();
while (isdigit(ch))
x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
return x;
}
int T,n,f[N],d[N][N],dis[N];
LL g[N][N],yg[N][N];
int cmpv_id;
bool cmp(int a,int b){
return g[cmpv_id][a]<g[cmpv_id][b];
}
void Getdis(int x,int y){
int k=0;
memset(f,0,sizeof f);
int v1=1,v2=1;
while (1){
while (v1<=n&&f[d[x][v1]])
v1++;
while (v2<=n&&f[d[y][v2]])
v2++;
if (v1>n&&v2>n)
break;
if (v1>n){
f[d[y][v2]]=1;
dis[++k]=g[y][d[y][v2++]];
}
else if (v2>n){
f[d[x][v1]]=1;
dis[++k]=g[x][d[x][v1++]];
}
else if (g[x][d[x][v1]]<=g[y][d[y][v2]]){
f[d[x][v1]]=1;
dis[++k]=g[x][d[x][v1++]];
}
else {
f[d[y][v2]]=1;
dis[++k]=g[y][d[y][v2++]];
}
}
}
void solve(){
n=read();
int tot=0;
for (int i=1;i<=n;i++)
for (int j=1;j<=n;j++)
yg[i][j]=g[i][j]=read(),tot=(tot+g[i][j])%mod;
tot=1LL*tot*((mod+1)/2)%mod;
for (int k=1;k<=n;k++)
for (int i=1;i<=n;i++)
for (int j=1;j<=n;j++)
g[i][j]=min(g[i][j],g[i][k]+g[k][j]);
for (int i=1;i<=n;i++){
for (int j=1;j<=n;j++)
d[i][j]=j;
cmpv_id=i;
sort(d[i]+1,d[i]+n+1,cmp);
}
int ans=0,e=n*(n-1)/2;
for (int x=1;x<=n;x++)
for (int y=x+1;y<=n;y++){
Getdis(x,y);
// printf("(%d,%d)\n",x,y);
// for (int i=1;i<=n;i++)printf("%d ",dis[i]);puts("");
ans=(1LL*(e-1)*yg[x][y]+ans)%mod;
ans=((ans+tot-yg[x][y])%mod+mod)%mod;
for (int i=1;i<=n;i++)
ans=(2LL*dis[i]*(n-i)+ans)%mod;
}
ans=1LL*ans*((mod+1)/2)%mod;
printf("%d\n",ans);
}
int main(){
T=read();
while (T--)
solve();
return 0;
}

  

2018牛客网暑假ACM多校训练赛(第十场)F Rikka with Line Graph 最短路 Floyd的更多相关文章

  1. 2018牛客网暑假ACM多校训练赛(第二场)E tree 动态规划

    原文链接https://www.cnblogs.com/zhouzhendong/p/NowCoder-2018-Summer-Round2-E.html 题目传送门 - 2018牛客多校赛第二场 E ...

  2. 2018牛客网暑假ACM多校训练赛(第三场)I Expected Size of Random Convex Hull 计算几何,凸包,其他

    原文链接https://www.cnblogs.com/zhouzhendong/p/NowCoder-2018-Summer-Round3-I.html 题目传送门 - 2018牛客多校赛第三场 I ...

  3. 2018牛客网暑假ACM多校训练赛(第三场)G Coloring Tree 计数,bfs

    原文链接https://www.cnblogs.com/zhouzhendong/p/NowCoder-2018-Summer-Round3-G.html 题目传送门 - 2018牛客多校赛第三场 G ...

  4. 2018牛客网暑假ACM多校训练赛(第三场)D Encrypted String Matching 多项式 FFT

    原文链接https://www.cnblogs.com/zhouzhendong/p/NowCoder-2018-Summer-Round3-D.html 题目传送门 - 2018牛客多校赛第三场 D ...

  5. 2018牛客网暑假ACM多校训练赛(第十场)H Rikka with Ants 类欧几里德算法

    原文链接https://www.cnblogs.com/zhouzhendong/p/NowCoder-2018-Summer-Round10-H.html 题目传送门 - https://www.n ...

  6. 2018牛客网暑假ACM多校训练赛(第十场)D Rikka with Prefix Sum 组合数学

    原文链接https://www.cnblogs.com/zhouzhendong/p/NowCoder-2018-Summer-Round10-D.html 题目传送门 - https://www.n ...

  7. 2018牛客网暑假ACM多校训练赛(第八场)H Playing games 博弈 FWT

    原文链接https://www.cnblogs.com/zhouzhendong/p/NowCoder-2018-Summer-Round8-H.html 题目传送门 - https://www.no ...

  8. 2018牛客网暑假ACM多校训练赛(第七场)I Tree Subset Diameter 动态规划 长链剖分 线段树

    原文链接https://www.cnblogs.com/zhouzhendong/p/NowCoder-2018-Summer-Round7-I.html 题目传送门 -  https://www.n ...

  9. 2018牛客网暑假ACM多校训练赛(第六场)I Team Rocket 线段树

    原文链接https://www.cnblogs.com/zhouzhendong/p/NowCoder-2018-Summer-Round6-I.html 题目传送门 - https://www.no ...

随机推荐

  1. mysql 命令行常用命令

    1.显示数据库列表.  show databases; 2.显示库中的数据表:  use mysql; show tables; 3.显示数据表的结构:  describe 表名; 4.建库:  cr ...

  2. 4)协程一(yeild)

    一:什么协程 协程: coroutine/coro - 轻量级线程(一个线程) - 调度由用户控制 - 有独立的寄存器上下文和栈 - 切换时保存状态,回来时恢复 二:协程和多线程比较 协程: coro ...

  3. mvc 模式和mtc 模式的区别

    首先说说Web服务器开发领域里著名的MVC模式,所谓MVC就是把Web应用分为模型(M),控制器(C)和视图(V)三层,他们之间以一种插件式的.松耦合的方式连接在一起,模型负责业务对象与数据库的映射( ...

  4. LeetCode(110):平衡二叉树

    Easy! 题目描述: 给定一个二叉树,判断它是否是高度平衡的二叉树. 本题中,一棵高度平衡二叉树定义为: 一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过1. 示例 1: 给定二叉树 [3, ...

  5. 【linux】Linux误删C基本运行库libc.so.6急救方法

    转自:http://www.cnblogs.com/fjping0606/p/4551475.html 下面全文都是拷贝的上面链接的内容. 首先普及一下关于libc.so.6的基本常识: libc.s ...

  6. python网络爬虫笔记(三)

    一.切片和迭代 1.列表生成式 2.生成器的generate,但是generate保存的是算法,所以可以迭代计算,没有必要,每次调用generate 二.iteration 循环 1.凡是作用于for ...

  7. vue-cli3.0 使用postcss-plugin-px2rem(推荐)和 postcss-pxtorem(postcss-px2rem)自动转换px为rem 的配置方法;

    如何在vue-cli3.0中使用postcss-plugin-px2rem 插件 插件的作用是 自动将vue项目中的px转换为rem . 为什么这三个中要推荐  postcss-plugin-px2r ...

  8. axure—日期函数

    日期函数 日期函数中实现倒计时的关键点:1)gettime()函数可以取到1970年1月1日的时间,我们用倒计时结束的时间减去当前时间就能得到倒计时需要循环显示的所有时间.2)此处的“d”是倒计时结束 ...

  9. Springboot+MyBatis+JPA集成

      1.前言 Springboot最近可谓是非常的火,本人也在项目中尝到了甜头.之前一直使用Springboot+JPA,用了一段时间发现JPA不是太灵活,也有可能是我不精通JPA,总之为了多学学Sp ...

  10. settings.py常见配置项

    settings.py常见配置项 1. 配置Django_Admin依照中文界面显示 LANGUAGE_CODE = 'zh-hans' 2. 数据库配置(默认使用sqlite3) 1 .默认使用的s ...