luoguP3403跳楼机 题解【同余最短路】

发布时间 2023-07-11 11:52:35作者: Kun_9

题面

题意:
可以发现操作四相当于是每次有了回到起点的机会,那么问题就变成了求满足:\(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;
}