题解 P3403 【跳楼机】

题目链接

Solution 跳楼机

分析:给定 (h,x,y,z),对于 (k in [1,h]),有多少个 (k) 满足 (ax+by+cz=k)

同余最短路


分析:学了一下同余最短路

我们把原题中 (h - 1) 方便处理,然后可以按照 模 (x) 把楼层分为若干个剩余类。那么对于一个剩余类,假设我们可以到达的最低的楼层为 (k),那么该剩余类里面所有 (geq k) 的楼层我们都可以到达。

然后 (forall i in [0,x)) ,连边 ((i,(i+y);mod;x)),边权为 (y),对于 (z) 同理,这样我们以 (0) 为起点跑一次最短路,就可以求出一个剩余类里面可以到达的最低楼层。

(dis[i]) 为剩余系 (i) 中可以到达的最低楼层,那么 (ans=sum_{i=0}^{x-1}lfloorfrac{h-dis[i]}{x} floor + 1),注意特判无法到达某个剩余类的情况

为了优化,我们一般选择 (x,y,z) 中最小的来划分剩余类

#include <iostream>
#include <queue>
#include <vector>
#include <cstring>
using namespace std;
typedef long long ll;
const int maxn = 1e5 + 100;
struct edge{int v,d;};
struct node{
    int u;
    ll h;
    bool operator < (const node &rhs)const{
        return h > rhs.h;
    }
};
vector<edge> G[maxn];
inline void addedge(int u,int v,int d){G[u].push_back(edge{v,d});}
ll h,x,y,z,dis[maxn],ans;
bool vis[maxn];
inline void dijkstra(int s){
    memset(dis,0x7f,sizeof(dis));
    dis[s] = 0;
    priority_queue<node> q;
    q.push(node{s,0});
    while(!q.empty()){
        int u = q.top().u;q.pop();
        if(vis[u])continue;
        vis[u] = 1;
        for(auto e : G[u]){
            if(dis[u] + e.d < dis[e.v]){
                dis[e.v] = dis[u] + e.d;
                q.push(node{e.v,dis[e.v]});
            }
        }
    }
}
int main(){
    cin >> h >> x >> y >> z;
    h--;
    for(int i = 0;i < x;i++)
        addedge(i,(i + y) % x,y),addedge(i,(i + z) % x,z);
    dijkstra(0);
    for(int i = 0;i < x;i++)
        if(dis[i] <= h)ans += (h - dis[i]) / x + 1;
    cout << ans << '
';
    return 0;
}
原文地址:https://www.cnblogs.com/colazcy/p/13909252.html