• 同余最短路


    同余最短路其实是一种优化最短路建图的方法。

    通常是解决给定m个整数,求这m个整数能拼凑出多少的其他整数(这m个整数可以重复取)或给定m个整数,求这m个整数不能拼凑出的最小(最大)的整数。

    我们通过一道例题来讲解。

    P3403 跳楼机

    简化一下题意:用a,b,c(这里用a,b,c来代替x,y,z)三个数能组成几个小于h的整数。$h leq 2^{63}-1$

    因为h过大所以直接建图显然是不行的,我们要优化空间。

    我们因为这个跳的顺序是无关的,所以每个数都可以由若干次b/c再加上若干次a而形成的。

    根据带余除法我们知道所有的整数数都可以写成ax+r的形式,其中a是除数,x是商而r是余数。

    我们求出通过b/c操作能到达的最小的mod a余数是r的数,然后用一些算法即可求出能到达多少小于h的整数(到时再讲)。

    这时我们同余最短路就该排上用场了。这个最小即可表示成最短路。

    我们可以让a来做这个除数(其实应该用最小的最优),则r属于$[0,a-1]$。

    我们要求出所有到达所有r的最小值。所以对于每个r建立一个点。

    它可以通过b,c到其它的数(点),所以我们对于每个点u连一条到v=(u+(b/c))%a的边,长度为(b/c)。

    现在从0开始跑最短路即可(初始化dis[0]=0)。

    设余数r的最短路为dis[r],则可以到$frac{h-dis[r]}{a}+1$个整数,统计答案。

    #include <bits/stdc++.h>
    using namespace std;
    const long long MAXA = 1e5 + 10; 
    struct node{
        long long pre, to, val;
    }edge[MAXA * 20];
    long long head[MAXA], tot;
    long long n, h;
    long long a[20];
    long long dis[MAXA], vis[MAXA];
    queue<long long> q;
    void add(long long u, long long v, long long l) {
        edge[++tot] = node{head[u], v, l};
        head[u] = tot;
    }
    void spfa() {
        memset(dis, 0x3f, sizeof(dis));
        dis[0] = 0;
        vis[0] = 1;
        q.push(0);
        while (!q.empty()) {
            long long x = q.front(); q.pop();
            for (long long i = head[x]; i; i = edge[i].pre) {
                long long y = edge[i].to;
                if (dis[y] > dis[x] + edge[i].val) {
                    dis[y] = dis[x] + edge[i].val;
                    if (!vis[y]) {
                        vis[y] = 1;
                        q.push(y);
                    }
                }
            }
            vis[x] = 0;
        }
    }
    long long solve(long long x) {
        long long ret = 0;
        for (long long i = 0; i < a[1]; i++) {
            if (dis[i] <= x) {
                ret += (x - dis[i]) / a[1] + 1;
            }
        }
        return ret;
    }
    int main() {
        n = 3;
        cin >> h;
        for (long long i = 1; i <= n; i++) {
            cin >> a[i];
        }
        for (long long i = 0; i < a[1]; i++) {
            for (long long j = 2; j <= n; j++) {
                add(i, (i + a[j]) % a[1], a[j]);
            }
        }
        spfa();
        cout << solve(h - 1);//他刚开始在1楼所以要-1
        return 0;
    }

    习题:

    [国家集训队]墨墨的等式

     

  • 相关阅读:
    PAT 1097. Deduplication on a Linked List (链表)
    PAT 1096. Consecutive Factors
    PAT 1095. Cars on Campus
    PAT 1094. The Largest Generation (层级遍历)
    PAT 1093. Count PAT's
    PAT 1092. To Buy or Not to Buy
    PAT 1091. Acute Stroke (bfs)
    CSS:word-wrap/overflow/transition
    node-webkit中的requirejs报错问题:path must be a string error in Require.js
    script加载之defer和async
  • 原文地址:https://www.cnblogs.com/zcr-blog/p/12631741.html
Copyright © 2020-2023  润新知