luoguP3403跳楼机 题解【同余最短路】
题意:
可以发现操作四相当于是每次有了回到起点的机会,那么问题就变成了求满足:\(Ax+By+Cz = k,k\leq h\) 所有的 \(k\)。
考虑忽略 \(x\),这样只需要求出所有的通过 \(y, z\) 能到达的小于 \(x\) 的方案(设为 \(f_i\)),最终的答案就是\(\sum_{i=0}^{x-1}(h - f_i) / x + 1\)。
考虑上面这个过程,可以通过同余最短路解决,具体到建图上可以为每个 \(mod\ x\) 同余类建立一个节点,最终的 \(f_i\) 就是从 \(1\)(起点)到 \(i\) 的最短路。
code:
点击查看代码
#include <bits/stdc++.h>
#define int long long
#define dub long double
#define mar(x) for(int i = head[x]; i; i = e[i].nxt)
#define car(a) memset(a, 0, sizeof(a))
#define cap(a, b) memcpy(a, b, sizeof(b))
const int inf = 1e9 + 7;
const int MAXN = 5e5;
using namespace std;
inline int read( ){
int x = 0 ; short w = 0 ; char ch = 0;
while( !isdigit(ch) ) { w|=ch=='-';ch=getchar();}
while( isdigit(ch) ) {x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
return w ? -x : x;
}
struct edge{
int u, v, w, nxt;
} e[MAXN];
struct node{
int p, w;
bool operator<(node x) const{
return w > x.w;
}
};
int head[MAXN], cnt;
int h, A, B, C, ans;
int dis[MAXN], vis[MAXN];
priority_queue<node> q;
void add(int u, int v, int w){
e[++cnt] = (edge){u, v, w, head[u]};
head[u] = cnt;
}
void dij( ){
memset(dis, 0x3f, sizeof(dis));
q.push({1, 0});
dis[1] = 1;
while(!q.empty( )){
int x = q.top( ).p; q.pop( );
if(vis[x]) continue;
vis[x] = 1;
for(int i = head[x]; i; i = e[i].nxt){
int y = e[i].v;
if(dis[x] + e[i].w < dis[y]){
dis[y] = dis[x] + e[i].w;
q.push({y, dis[y]});
}
}
}
}
signed main( ){
h = read( ); A = read( ); B = read( ); C = read( );
if(A < B) swap(A, B);
if(A < C) swap(A, C);
if(A == 1 or B == 1 or C == 1){
cout << h << endl;
return 0;
}
for(int i = 0; i < A; i++)
add(i, (i + B) % A, B),
add(i, (i + C) % A, C);
dij( );
for(int i = 0; i < A; i++)
if(dis[i] <= h) ans += (h - dis[i]) / A + 1;
cout << ans;
return 0;
}