目录

CF1366F-Jog Around The Graph

CF1366F-Jog Around The Graph

题目:

题目描述:

You are given a simple weighted connected undirected graph, consisting of $ n $ vertices and $ m $ edges.

A path in the graph of length $ k $ is a sequence of $ k+1 $ vertices $ v_1, v_2, \dots, v_{k+1} $ such that for each $ i $ $ (1 \le i \le k) $ the edge $ (v_i, v_{i+1}) $ is present in the graph. A path from some vertex $ v $ also has vertex $ v_1=v $ . Note that edges and vertices are allowed to be included in the path multiple times.

The weight of the path is the total weight of edges in it.

For each $ i $ from $ 1 $ to $ q $ consider a path from vertex $ 1 $ of length $ i $ of the maximum weight. What is the sum of weights of these $ q $ paths?

Answer can be quite large, so print it modulo $ 10^9+7 $ .

输入格式:

The first line contains a three integers $ n $ , $ m $ , $ q $ ( $ 2 \le n \le 2000 $ ; $ n - 1 \le m \le 2000 $ ; $ m \le q \le 10^9 $ ) — the number of vertices in the graph, the number of edges in the graph and the number of lengths that should be included in the answer.

Each of the next $ m $ lines contains a description of an edge: three integers $ v $ , $ u $ , $ w $ ( $ 1 \le v, u \le n $ ; $ 1 \le w \le 10^6 $ ) — two vertices $ v $ and $ u $ are connected by an undirected edge with weight $ w $ . The graph contains no loops and no multiple edges. It is guaranteed that the given edges form a connected graph.

输出格式:

Print a single integer — the sum of the weights of the paths from vertex $ 1 $ of maximum weights of lengths $ 1, 2, \dots, q $ modulo $ 10^9+7 $ .

样例:

样例输入 1:

1
2
3
4
5
6
7
8
9
7 8 25
1 2 1
2 3 10
3 4 2
1 5 2
5 6 7
6 4 15
5 3 1
1 7 3

样例输出 1:

1
4361

样例输入 2:

1
2
2 1 5
1 2 4

样例输出 2:

1
60

样例输入 3:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
15 15 23
13 10 12
11 14 12
2 15 5
4 10 8
10 2 4
10 7 5
3 10 1
5 6 11
1 13 8
9 15 4
4 2 9
11 15 1
11 12 14
10 8 12
3 6 11

样例输出 3:

1
3250

样例输入 4:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
5 10 10000000
2 4 798
1 5 824
5 2 558
4 1 288
3 4 1890
3 1 134
2 3 1485
4 5 284
3 5 1025
1 2 649

样例输出 4:

1
768500592

思路:

1.先考虑 $k\leq m$ 的情况,可以直接用 $O(N\times M)$ 的暴力 dp 解决

2.$k > M$ 时,最长路径的最后一段一定是在一条边上来回走。 考虑枚举最后来回走的那一条边,再枚举走到那条边的时间,时间 一定在 $M$ 以内。斜率优化 dp 即可

实现:

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
#include "ybwhead/ios.h"
#define int long long
int n, m;
long long q;
const int maxn = 2e3 + 10;
struct edge
{
    int v, nxt, w;
} e[maxn << 1];
int head[maxn], tot;
int hv[maxn];
const int mod = 1e9 + 7;
const int inv2 = mod / 2 + 1;
void __ADD(int u, int v, int w)
{
    e[++tot].v = v;
    e[tot].w = w;
    e[tot].nxt = head[u];
    head[u] = tot;
    hv[v] = max(hv[v], w);
}
void add(int u, int v, int w)
{
    __ADD(u, v, w);
    __ADD(v, u, w);
}
int d[maxn], nd[maxn];

struct frac
{
    long long x, y;
    frac(long long a, long long b)
    {
        if (b < 0)
            a = -a, b = -b;
        x = a, y = b;
    }
    bool operator<(frac b)
    {
        return x * b.y <= y * b.x;
    }
};
struct lin
{
    long long m, c;
    frac xx(const lin &l) { return frac(c - l.c, l.m - m); }
} fi[maxn];
deque<lin> ch;
int cmp(lin a, lin b)
{
    if (a.m ^ b.m)
        return a.m < b.m;
    return a.c > b.c;
}
int cmp1(lin a, lin b)
{
    return a.m == b.m;
}
int add(int a, int b)
{
    a += b;
    if (a >= mod)
        a -= mod;
    if (a < 0)
        a += mod;
    return a;
}

int mul(int a, int b)
{
    return a * 1ll * b % mod;
}

int calc(int a1, int d, int n)
{
    return mul(mul(n, inv2), add(mul(2, a1), mul(add(n, -1), d)));
}

signed main()
{
    yin >> n >> m >> q;
    for (int i = 1; i <= m; i++)
    {
        int u, v, w;
        yin >> u >> v >> w;
        add(u, v, w);
    }
    memset(d, -0x7f7f7f7f, sizeof(d));
    d[1] = 0;
    long long ans = 0;
    for (int x = 1; x <= m; x++)
    {
        long long mx = 0;
        for (int i = 1; i <= n; i++)
            mx = max(mx, (long long)d[i]);
        if (x != 1)
            ans = add(ans, mx % mod);
        for (int i = 1; i <= n; i++)
            nd[i] = d[i];
        for (int u = 1; u <= n; u++)
        {
            for (int i = head[u]; i; i = e[i].nxt)
            {
                int v = e[i].v;
                nd[v] = max(nd[v], d[u] + e[i].w);
            }
        }
        for (int i = 1; i <= n; i++)
            d[i] = nd[i];
    }
    for (int i = 1; i <= n; i++)
        fi[i] = (lin){hv[i], d[i]};
    sort(fi + 1, fi + n + 1, cmp);
    int mm = unique(fi + 1, fi + n + 1, cmp1) - fi - 1;
    for (int i = 1; i <= mm; i++)
    {
        // cout << fi[i].m << ' ' << fi[i].c << endl;
        while (ch.size() >= 2 && fi[i].xx(ch.back()) < ch.back().xx(ch[ch.size() - 2]))
            ch.pop_back();
        ch.push_back(fi[i]);
    }
    long long prv = 0;
    q -= m;
    for (int i = 0; i < ch.size() - 1; i++)
    {
        frac f = ch[i].xx(ch[i + 1]);
        if (f.x < 0)
            continue;
        long long lst = min((long long)q, f.x / f.y);
        if (lst < prv)
            continue;
        ans = add(ans, calc((ch[i].c + ch[i].m * prv) % mod, ch[i].m % mod, lst - prv + 1));
        prv = lst + 1;
    }
    ans = add(ans, calc((ch.back().c + ch.back().m * prv) % mod, ch.back().m % mod, q - prv + 1)) % mod;
    yout << (ans + mod) % mod << endl;
    return 0;
}