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;
}