跳樓機(同餘類最短路)

~~這題是在幹嗎啊?怕不是又是a*b-a-b~~c++

然而萬萬沒想到,這是到圖論題spa

\(dis[i]\)爲在\(%x\)意義下,能到達的樓層爲i的最小值code

也就是說只用\(y, z\)能到達的樓層在\(%x\)意義下的最小值get

不難推出方程it

\[dis[(i + y) \% x] = min(dis[(i + y) \% x], dis[i] + y)\]class

\[dis[(i + z) \% x] = min(dis[(i + z) \% x], dis[i] + z)\]queue

看到這兩個柿子,不難想到圖論中的最短路,因此咱們能夠用最短路來求出\(0~x\)\(dis\)統計

求除了dis之後有什麼用呢?di

跟據dis定義,咱們能夠經過y, z到達的最小樓層,以該樓層爲起點(設該點爲s),咱們能夠跳到\(s + x\), \(s + 2 * x\)……vi

總共咱們能夠跳到\((H - dis[i]) / x + 1\)

不難證實,每一個樓層是不會被重複統計的

因而咱們就能夠以優秀的複雜度完成此題了

#include<bits/stdc++.h>
using namespace std;
#define il inline
#define re register
#define int long long
il int read() {
    re int x = 0, f = 1; re char c = getchar();
    while(c < '0' || c > '9') { if(c == '-') f = -1; c = getchar();}
    while(c >= '0' && c <= '9') x = x * 10 + c - 48, c = getchar();
    return x * f;
}
#define rep(i, s, t) for(re int i = s; i <= t; ++ i)
#define mem(k, p) memset(k, p, sizeof(k))
#define maxn 100005
int n, m, x, y, z, dis[maxn], vis[maxn], ans;
queue<int>q;
il void SPFA() {
    mem(dis, 63), q.push(1 % x), dis[1 % x] = 1;
    while(!q.empty()) {
        int u = q.front(); q.pop(), vis[u] = 0;
        int v = (u + y) % x;
        if(dis[v] > dis[u] + y) {
            dis[v] = dis[u] + y;
            if(!vis[v]) vis[v] = 1, q.push(v);
        }
        v = (u + z) % x;
        if(dis[v] > dis[u] + z) {
            dis[v] = dis[u] + z;
            if(!vis[v]) vis[v] = 1, q.push(v);
        }
    }
}
signed main() {
    n = read(), x = read(), y = read(), z = read();
    SPFA();
    rep(i, 0, x - 1) if(dis[i] <= n) ans += (n - dis[i]) / x + 1;
    printf("%lld", ans);
    return 0;
}
相關文章
相關標籤/搜索