跳楼机(最短路)

跳楼机

题目背景

DJL为了避免成为一只咸鱼,来找srwudi学习压代码的技巧。

题目描述

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

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

  1. 向上移动x层;

  2. 向上移动y层;

  3. 向上移动z层;

  4. 回到第一层。

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

输入输出格式

输入格式:

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

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

输出格式:

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

输入输出样例

输入样例#1: 复制

15
4 7 9

输出样例#1: 复制

9

输入样例#2: 复制

33333333333
99005 99002 100000

输出样例#2: 复制

33302114671

说明

可以到达的楼层有:1,5,8,9,10,12,13,14,15

想不出来不要死磕这一题,先看看第三题。。。。

1<=h<=2^63-1

1<=x, y, z<=100000

题解


这是一道思路非常奇妙的题目。
我去百度了一下,发现题解都不是很清楚。
我也不知道我能不能说清楚。

首先设原方程为ax+by+cz=[1,h]。
我们保证x有解。那么by+cz=[1,h]%x。
接下来我们假设一个点是走y步可以到的。
那么每走一次y步,就可以往后一直用x步走。
走一次z步同理。
把y和z单独拿出来看。
枚举0到x-1的点。(i+y)%x就是当x走不了的情况下,y可以走到的楼层。
而(i+y)%x需要走多少次y由i—>(i+y)%x的最短路推出来。
z同理。
那么你可以会问方程是by+cz。
而我们只单独讨论了。
实际上这已经在最短路上跑了出来。因为0到x-1是共享的。
用dis[i]表示到i的最短距离。那么贡献便是(H-dis[i])/x+1的。


代码

#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<iostream>
#include<queue>
#define ll long long
using namespace std;
const int N=500001;
ll H,x,y,z;
ll vis[N],dis[N];
ll num,head[N],ans;
struct node{
    int to,v,nex;
}e[N];
void add(int from,int to,int v){
    num++;
    e[num].to=to;
    e[num].v=v;
    e[num].nex=head[from];
    head[from]=num;
}

ll read(){
    ll x=0,w=1;char ch=getchar();
    while(ch>'9'||ch<'0'){if(ch=='-')w=-1;ch=getchar();}
    while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
    return x*w;
}

void dijkstra(){
    priority_queue<pair<ll,int> >q;
    memset(dis,63,sizeof(dis));dis[1%x]=1;
    q.push(make_pair(0,1%x));
    while(!q.empty()){
        int u=q.top().second;q.pop();
        if(vis[u])continue;vis[u]=1;
        for(int i=head[u];i;i=e[i].nex){
            int v=e[i].to;
            if(dis[v]>dis[u]+e[i].v){
                dis[v]=dis[u]+e[i].v;
                q.push(make_pair(-dis[v],v));
            }
        }
    }
}

int main(){	
    H=read();
    x=read();y=read();z=read();
    if(x==1)printf("%lld\n",H),exit(0);
    for(int i=0;i<x;i++){
        add(i,(i+y)%x,y);
        add(i,(i+z)%x,z);
    }
    dijkstra();
    for(int i=0;i<x;i++)if(dis[i]<=H)ans+=(H-dis[i])/x+1;
    printf("%lld\n",ans);
    return 0;
}
posted @ 2018-09-04 21:42  Epiphyllum_thief  阅读(251)  评论(0编辑  收藏  举报