卧薪尝胆,厚积薄发。
Elevator
Date: Sat Jul 07 11:24:37 CST 2018
In Category:
NoCategory
Description:
楼中有一个电梯,电梯可以上升
$a$
层,上升
$b$
层,上升
$c$
层,回到
$1$
层,问能到达前
$h$
层楼中的几层。
$1\le h \le 10^{18},1\le a,b,c \le 100000$
Solution:
同余类
$BFS$
,将层数按
$\%a$
的值划分为
$0,1,\dots,(a-1)$
这些同余系。
同余系
$i$
向
$(i+b)\%a$
和
$(i+c)\%a$
连边权分别为
$b$
和
$c$
的边,
$d[1]=1$
,求最短路即可得到到各个同余系的最低楼层。于是就知道了每个同余系能到的楼层个数,累加即可。
注意存在
$1$
时的特判。
Code:
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<queue>
#include<cstring>
using namespace std;
typedef long long ll;
ll h;
int a,b,c;
#define MAXN 100010
struct edge
{
int to,nxt;
ll v;
}e[MAXN * 2 * 2];
int edgenum = 0;
int lin[MAXN] = {0};
void add(int a,int b,ll c)
{
++edgenum;e[edgenum].to = b;e[edgenum].v = c;e[edgenum].nxt = lin[a];lin[a] = edgenum;
return;
}
ll d[MAXN];
bool v[MAXN];
int main()
{
scanf("%lld%d%d%d",&h,&a,&b,&c);
if(a == 1 || b == 1 || c == 1)
{
cout << h << endl;
return 0;
}
if(a > b)swap(a,b);
if(a > c)swap(a,c);
for(int i = 0;i < a;++i)add(i,(i + b) % a,(ll)b);
for(int i = 0;i < a;++i)add(i,(i + c) % a,(ll)c);
memset(d,0x3f,sizeof(d));
memset(v,0,sizeof(v));
d[1] = 1;
queue<int> q;
q.push(1);
v[1] = true;
while(!q.empty())
{
int k = q.front();q.pop();
v[k] = false;
for(int i = lin[k];i != 0;i = e[i].nxt)
{
if(d[e[i].to] > d[k] + e[i].v)
{
d[e[i].to] = d[k] + e[i].v;
if(!v[e[i].to])
{
v[e[i].to] = true;
q.push(e[i].to);
}
}
}
}
ll ans = 0;
for(int i = 0;i < a;++i)
{
if(h >= d[i])ans += ((h - i) / a) - ((d[i] - i) / a) + 1;
}
cout << ans << endl;
return 0;
}
In tag:
图论-同余类最短路
Copyright © 2020
wjh15101051
ღゝ◡╹)ノ♡