• 【BZOJ3482】【JZOJ3238】[COCI2013]hiperprostor 超空间旅行


    题目大意

    题目链接
    给出一个(p)个点(r)条边的有向图,某些边长度给定,某些边长度是一个未知的正整数(x)(都是(x))。有(q)个询问,每次询问(s)(t)的最短路长度有几种可能,以及这些可能的长度之和。

    分析

    可以发现任意一条(s)(t)的最短路都能表示成(kx+b)的形式;那么我们可以设(f[i][j])表示由(s)走到(i)(k=j)(b)的最小值,用最短路算法求出(f)数组。那么此时(s)(t)的最短路就可以用若干个一次函数(kx+f[t][k])表示了。

    把这些一次函数变成直线放在坐标系,考虑两条直线,在交点两侧两条直线分别更优。于是我们可以考虑把这些直线的上凸壳做出来,显然相邻两条直线的交点横坐标是递增的,这些交点的横坐标把(x)轴分成若干段,我们分别计算每一段的贡献即可。

    注意判掉一些不合法的情况。注意常数优化。

    Code

    #include <cmath>
    #include <cstdio>
    #include <cstring>
    
    typedef long long ll;
    const int N = 507, M = 10007;
    
    char ch;
    int n, m, q, s, t;
    int tot, st[N], to[M], nx[M], len[M];
    void add(int u, int v, int w) { to[++tot] = v, nx[tot] = st[u], len[tot] = w, st[u] = tot; }
    
    int head, tail, que[N * N * 14][2], vis[N][N];
    ll ans1, ans2, f[N][N];
    void spfa()
    {
        memset(f, 0x3f, sizeof(f));
        memset(vis, 0, sizeof(vis));
        head = 1, que[tail = 1][0] = s, que[tail][1] = 0, f[s][0] = 0, vis[s][0] = 1;
        while (head <= tail)
        {
            int u = que[head][0], p = que[head][1]; head++;
            vis[u][p] = 0;
            for (register int i = st[u], v, j, t; i; i = nx[i])
            {
                v = to[i], j = p + (len[i] == -1);
    			if (j > n - 1) continue;
                t = f[u][p] + (len[i] == -1 ? 0 : len[i]);
                if (t < f[v][j])
                {
                    f[v][j] = t;
                    if (!vis[v][j]) que[++tail][0] = v, que[tail][1] = j, vis[v][j] = 1;
                }
            }
        }
    }
    
    double inter(int k0, ll b0, int k1, ll b1) { return (b1 - b0) * 1.0 / (k0 - k1);  }
    int top;
    ll stk[N][2];
    void solve()
    {
        int flag = 1; for (int i = 0; i <= n - 1; i++) if (f[t][i] < f[506][506]) { flag = 0; break; }
        if (flag) { printf("0 0
    "); return; }
        flag = 1; for (int i = 1; i <= n - 1; i++) if (f[t][i] < f[506][506]) { flag = 0; break; }
        if (!flag && f[t][0] >= f[506][506]) { printf("inf
    "); return; }
        ans1 = ans2 = top = 0;
        for (int i = n - 1; i >= 0; i--)
        {
            if (f[t][i] > f[t][0]) continue;
            if (!top) { stk[++top][0] = i, stk[top][1] = f[t][i]; continue; }
            while ((top > 0 && f[t][i] < stk[top][1]) || (top > 1 && inter(stk[top - 1][0], stk[top - 1][1], i, f[t][i]) <= inter(stk[top - 1][0], stk[top - 1][1], stk[top][0], stk[top][1]))) top--;
            stk[++top][0] = i, stk[top][1] = f[t][i];
        }
        ll l, r;
        for (int i = 1; i <= top; i++)
        {
            if (i == 1) l = 1;
            else l = r + 1;
            if (i == top) r = l;
            else r = inter(stk[i][0], stk[i][1], stk[i + 1][0], stk[i + 1][1]);
            if (inter(stk[i][0], stk[i][1], stk[i + 1][0], stk[i + 1][1]) == r) r--;
            ans1 += r - l + 1, ans2 += (stk[i][0] * l + stk[i][1] + stk[i][0] * r + stk[i][1]) * (r - l + 1) / 2;
        }
        printf("%lld %lld
    ", ans1, ans2);
    }
    
    int main()
    {
    	scanf("%d%d", &n, &m);
    	for (int i = 1, a = 0, b = 0, c; i <= m; i++)
    	{
            scanf("%d%d", &a, &b), c = 0;
            for (ch = getchar(); ch < '0' || ch > '9'; ch = getchar()) if (ch == 'x') { c = -1; break; }
            if (c != -1) for (; ch >= '0' && ch <= '9'; ch = getchar()) c = c * 10 + ch - '0';
    		add(a, b, c);
    	}
    	scanf("%d", &q);
    	while (q--)
    	{
    		scanf("%d%d", &s, &t);
            spfa(), solve();
    	}
    	return 0;
    }
    
  • 相关阅读:
    Kubernetes Admission Controller解析
    容器化Node Exporter对主机磁盘使用率的监控问题
    Prometheus监控指标的label注入方法
    Prometheus告警模型分析
    Kubernetes Controller执行框架解析
    深入理解Istio核心组件之Pilot
    Prometheus存储模型分析
    如何利用Prometheus监控你的应用
    Prometheus在Kubernetes下的服务发现机制
    JSON字符串和js对象转换
  • 原文地址:https://www.cnblogs.com/zjlcnblogs/p/11173226.html
Copyright © 2020-2023  润新知