POJ 3539 Elevator

Description
Edward works as an engineer for Non-trivial Elevators: Engineering, Research and Construction (NEERC). His new task is to design a brand new elevator for a skyscraper with h floors.
Edward has an idée fixe: he thinks that four buttons are enough to control the movement of the elevator. His last proposal suggests the following four buttons:
Move a floors up.
Move b floors up.
Move c floors up.
Return to the first floor.
Initially, the elevator is on the first floor. A passenger uses the first three buttons to reach the floor she needs. If a passenger tries to move a, b or c floors up and there is no such floor (she attempts to move higher than the h-th floor), the elevator doesn’t move.
To prove his plan worthy, Edward wants to know how many floors are actually accessible from the first floor via his elevator. Help him calculate this number.
Input
The first line of the input file contains one integer h — the height of the skyscraper (1 ≤ h ≤ 1018).
The second line contains three integers a, b and c — the parameters of the buttons (1 ≤ a, b, c ≤ 100 000).
Output
Output one integer number — the number of floors that are reachable from the first floor.
Sample Input
15
4 7 9
Sample Output
9


题意:一栋h层的楼(h <= 10^18)的电梯上一共4个按钮:上升a层,上升b层,上升c层(a, b, c <= 10^5),和下降至1层,初始在1层,问有多少层通过电梯可达。
假如我们现在电梯的运行是在模a的同余类下进行,就是说,如果可以达到i,那么i+k*a都可以达到。
可以想象一共有a个节点,dis[i]表示只用b,c可以到达的%a==i的最小长度,用spfa可以求出。
思考如果d[i] <= h,就是说可以在h层之前到达第j层,j % a == i,那么j+k*a也是可以到达,对于每个d[i] <= h的i都求出k,求和即为答案。


#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<queue>
using namespace std;
const long long inf = 1000000000ll * 1000000000ll + 10ll;
queue<int>q;
bool vis[100005];
long long h,ans,dis[100005];
int a,b,c;
int main()
{
    scanf("%lld%d%d%d",&h,&a,&b,&c);
    if(a>b)
        swap(a,b);
    if(a>c)
        swap(a,c);
    for(int i=0;i<=a-1;i++)
        dis[i]=inf;
    dis[1%a]=1;
    q.push(1%a);
    vis[1%a]=1;
    while(!q.empty())
    {
        int u=q.front();
        q.pop();
        if(dis[(u+b)%a]>dis[u]+b)
        {
            dis[(u+b)%a]=dis[u]+b;
            if(!vis[(u+b)%a])
            {
                vis[(u+b)%a]=1;
                q.push((u+b)%a);
            }
        }
        if(dis[(u+c)%a]>dis[u]+c)
        {
            dis[(u+c)%a]=dis[u]+c;
            if(!vis[(u+c)%a])
            {
                vis[(u+c)%a]=1;
                q.push((u+c)%a);
            }
        }
        vis[u]=0;
    }
    for(int i=0;i<=a-1;++i)
        if(dis[i]<=h)
            ans+=(h-dis[i])/a+1;
    printf("%lld\n",ans);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值