同余最短路


同余最短路其實是一種優化最短路建圖的方法。

通常是解決給定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;
}

習題:

[國家集訓隊]墨墨的等式

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM