分析:给定 \(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}\lfloor\frac{h-dis[i]}{x}\rfloor + 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 << '\n';
return 0;
}