题目描述
Srwudi的家是一幢h层的摩天大楼。由于前来学习的蒟蒻越来越多,srwudi改造了一个跳楼机,使得访客可以更方便的上楼。

经过改造,srwudi的跳楼机可以采用以下四种方式移动:

向上移动x层;

向上移动y层;

向上移动z层;

回到第一层。

一个月黑风高的大中午,DJL来到了srwudi的家,现在他在srwudi家的第一层,碰巧跳楼机也在第一层。DJL想知道,他可以乘坐跳楼机前往的楼层数。

输入格式
第一行一个整数h,表示摩天大楼的层数。

第二行三个正整数,分别表示题目中的x, y, z。

输出格式
一行一个整数,表示DJL可以到达的楼层数。

输入输出样例
输入 #1复制

15
4 7 9

输出 #1复制
9

输入 #2复制
33333333333
99005 99002 100000

输出 #2复制
33302114671


同余最短路。

我们考虑d[i]的含义为,能到达的 mod x == i的最小楼层。并且只用操作2和操作3.

然后对于每一个都能加上 k倍的x。

所以答案就为:ans+=(h−d[i])/x+1;


AC代码:

#pragma GCC optimize(2)
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e5+10;
int h,x,y,z,res,d[N];
int head[N],nex[N<<1],to[N<<1],w[N<<1],tot;
inline void add(int a,int b,int c){
	to[++tot]=b; nex[tot]=head[a]; w[tot]=c; head[a]=tot;
}
void spfa(){
	memset(d,0x3f,sizeof d); queue<int> q;	int vis[N]={0};
	d[1]=1; q.push(1); vis[1]=1;
	while(q.size()){
		int u=q.front();	q.pop();	vis[u]=0;
		for(int i=head[u];i;i=nex[i]){
			if(d[to[i]]>d[u]+w[i]){
				d[to[i]]=d[u]+w[i];
				if(!vis[to[i]])	vis[to[i]]=1,q.push(to[i]);
			}
		}
	}
}
signed main(){
	cin>>h>>x>>y>>z;
	if(x==1||y==1||z==1)	return printf("%lld\n",h),0;
	for(int i=0;i<x;i++)	add(i,(i+y)%x,y),add(i,(i+z)%x,z);
	spfa();
	for(int i=0;i<x;i++)	if(d[i]<=h)	res+=(h-d[i])/x+1;
	cout<<res<<endl;
	return 0;
}