【HNOI2016模拟4.14】A

来源:互联网 发布:知乎查看自己的匿名 编辑:程序博客网 时间:2024/06/06 12:42

题目大意:

给你一无向图,无重边,无自环。
dis1>u表示点1到点u的最短距离。
第k个时刻边l的距离等于它原来的距离加上k。
现在让你求第0..T时刻的ni=2dis1>i的和。

题解:

fi,j表示经过的边数不超过i,从1到j的最短距离(不算时刻的)。
这玩意可以O(nn)处理。
容易想到这个数组是递减的。
现在具体到每一个点j,我们发现,在不同时刻下,经过不同的边数的最短距离(算时刻的)一条直线。
如图:
这里写图片描述
x轴就是时刻,y轴是它对应的最短距离。
这些直线的斜率是i,与y轴交点是fi,j
我们需要知道每一个最低点,那么其实把最低点连起来,它是一个分段函数,并且不会超过n段,因为本来就只有n条直线。
这个怎么求呢?
%%%毛爷爷说用凸壳。
蒟蒻不会凸壳算法,蒟蒻只会用单调栈暴力。
对于两条直线l1,l2,使l1的斜率小于l2的斜率,如果它们的交点为(x,y),若当前时刻是<x的,则l2更小,否则l1更小。
这个可以作为单调栈的判断条件:
对于三条直线l1,l2,l3,使l1的斜率<l2的斜率<l3的斜率,l1、l2的交点是(x1,y1),l2、l3的交点是(x2,y2),如果x2<=x1,那么就没l2的事了。

Code:

#include<cmath>#include <cstdio>#define ll long long#define ld long double#define fo(i, x, y) for(ll i = x; i <= y; i ++)#define fd(i, x, y) for(ll i = x; i >= y; i --)#define min(a, b) ((a) < (b) ? (a) : (b))#define max(a, b) ((a) > (b) ? (a) : (b))using namespace std;const ll N = 2505, M = 5005, mo = 1e9 + 7, ni_2 = 5e8 + 4;ll n, m, T, d[M];ll f[N][N];ll ans;struct node {    ll a, b, c;}b[M * 2];void Init() {    scanf("%lld %lld %lld", &n, &m, &T);    fo(i, 1, m) scanf("%lld %lld %lld", &b[i].a, &b[i].b, &b[i].c);}void End() {    fo(i, 0, n) fo(j, 1, n) f[i][j] = 1e15;    f[0][1] = 0;    fo(i, 1, n) {        fo(j, 1, m)            f[i][b[j].a] = min(f[i][b[j].a], f[i - 1][b[j].b] + b[j].c),            f[i][b[j].b] = min(f[i][b[j].b], f[i - 1][b[j].a] + b[j].c);    }    fo(i, 1, n) fo(j, 1, n) f[j][i] = min(f[j - 1][i], f[j][i]);    fo(i, 2, n) {        d[0] = 1; d[1] = n;        fd(j, n - 1, 1) {            while(d[0] > 1) {                ld x = (ld)(f[d[d[0]]][i] - f[j][i]) / (j - d[d[0]]);                ld xx = (ld)(f[d[d[0] - 1]][i] - f[d[d[0]]][i]) / (d[d[0]] - d[d[0] - 1]);                if(x <= xx) d[0] --; else break;            }            d[++ d[0]] = j;        }        ll la = T + 1;        fd(j, d[0], 2) {            ll x = ceil((ld)(f[d[j - 1]][i] - f[d[j]][i]) / (d[j] - d[j - 1]));            if(x < la) {                la --;                x = max(x, 0);                ll l = x * d[j] + f[d[j]][i], r = la * d[j] + f[d[j]][i];                ans += (ll) (l + r)  % mo * (la - x + 1) % mo * ni_2, ans %= mo;                la = x;            }        }        if(la > 0) {            la --;            ll l = f[d[1]][i], r = f[d[1]][i] + d[1] * la;            ans += (ll) (l + r) % mo * (la + 1) % mo * ni_2, ans %= mo;        }    }    printf("%lld", ans);}int main() {    Init();    End();}