#同余最短路#洛谷 3403 跳楼机

题目


分析

如果\(x,y,z\)有一个是1答案肯定是大楼层数
首先回到第一层显然是没有用的,考虑bfs,显然会TLE
但是在此过程中可以发现有很多冗余状态(比如说不断加\(x\)
考虑以\(x\)为模数在这个同余系中,
求出一个点\(y\)跳到这个点的最小层数\(dis=\min \{y+kx\}\)
如果\(dis<=n\)那么就能产生\((n-dis)/x+1(它自己)\)的贡献
显然跳的过程可以用同余最短路实现


代码

#include <cstdio>
#include <cstring>
#include <queue>
#define rr register
using namespace std;
const int N=100011; typedef long long lll;
struct node{int y,w,next;}e[N<<1]; queue<int>q;
int X,Y,Z,as[N],k; lll n,dis[N],ans; bool v[N];
inline void add(int x,int y,int w){e[++k]=(node){y,w,as[x]}; as[x]=k;}
signed main(){
	memset(as,-1,sizeof(as)),memset(dis,0x3f,sizeof(dis));
	scanf("%lld%d%d%d",&n,&X,&Y,&Z);
	if (X==1||Y==1||Z==1) return !printf("%lld",n);
	for (rr int i=0;i<X;++i)
	    add(i,(i+Y)%X,Y),add(i,(i+Z)%X,Z);
	q.push(1),dis[1]=1,v[1]=1;
	while (q.size()){
		rr int x=q.front(); q.pop();
		for (rr int i=as[x];~i;i=e[i].next)
		if (dis[e[i].y]>dis[x]+e[i].w){
			dis[e[i].y]=dis[x]+e[i].w;
			if (!v[e[i].y]) v[e[i].y]=1,q.push(e[i].y);
		}
		v[x]=0;
	}
	for (rr int i=0;i<X;++i)
	if (dis[i]<=n) ans+=(n-dis[i])/X+1;
	return !printf("%lld",ans);
}
posted @ 2020-08-18 21:51  lemondinosaur  阅读(85)  评论(0编辑  收藏  举报