http://acm.hdu.edu.cn/showproblem.php?pid=5636
Problem Description There is a path graph G=(V,E) with n vertices. Vertices are numbered from 1 to n and there is an edge with unit length between i and i+1 (1≤i<n) . To make the graph more interesting, someone adds three more edges to the graph. The length of each new edge is 1 .
Input There are multiple test cases. The first line of input contains an integer T , indicating the number of test cases. For each test case:
Output For each test cases, output an integer S=(∑i=1mi⋅zi) mod (109+7) , where zi is the answer for i -th query.
Sample Input 1 10 2 2 4 5 7 8 10 1 5 3 1
Sample Output 7
Source |
一开始没做出来,参考博客懂了。
dist[i][j]存储的是离散化后的六个点的距离,a[i]存储的是六个点,计算两点之间距离时,直接做差或经过六个点中的几个点,用floyd跑一遍
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define LL long long
#define M 7
LL dist[M][M];
int a[M];
int abs(int a)
{
return a < 0 ? (-a) : a;
}
void floyd()
{
for(int k=1; k<M; k++)
{
for(int i=1; i<M; i++)
{
for(int j=1; j<M; j++)
{
dist[i][j] = dist[j][i] = min(dist[i][j], dist[i][k] + dist[k][j]);
}
}
}
}
int main()
{
int t, n, m;
LL mod = 1e9+7;
scanf("%d", &t);
while(t--)
{
scanf("%d%d", &n, &m);
for(int i=1; i<=6; i++)
{
scanf("%d", &a[i]);//六个点
}
for(int i=1; i<M; i++)//离散化一下使得 i, j直接表示 ai,aj
{
for(int j=1; j<M; j++)
{
dist[i][j] = abs(a[i] - a[j]);//六个点的距离;
}
}
dist[1][2] = dist[2][1] = 1;//缩短距离,离散化这六个点的距离
dist[3][4] = dist[4][3] = 1;//
dist[5][6] = dist[6][5] = 1;//
floyd();//求六个点之间的最短距离
LL ans = 0, flag = 0;
int x, y;
for(int i=1; i<=m; i++)
{
flag = 0;
scanf("%d%d", &x, &y);
flag = abs(x - y);
for(int j=1; j<M; j++)
{
for(int k=1; k<M; k++)
{
//dist[i][j]存储的是这六个点的距离;
flag = min(flag, abs(x - a[k]) + abs(y - a[j]) + dist[k][j]);//计算最短距离
flag = min(flag, abs(y - a[k]) + abs(x - a[j]) + dist[k][j]);//就相当于这六个点离散化
}
}
ans += (flag * i) % mod;
ans %= mod;
}
printf("%lld\n", ans);
}
return 0;
}