P3403 跳楼机(同余最短路+奇妙建图)

题目传送门

题意

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

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

  • 向上移动 x 层;
  • 向上移动 y 层;
  • 向上移动 z 层;
  • 回到第一层。
    一个月黑风高的大中午,DJL 来到了 srwudi 的家,现在他在 srwudi 家的第一层,碰巧跳楼机也在第一层。DJL 想知道,他可以乘坐跳楼机前往的楼层数。

思路

同余最短路,很显然的是,如果 层数\(h_0\)是可以抵达的,那么\(h_0+k*x\)的所有楼层都是可以抵达的,那么我们只有操作2和操作3,从他们可以抵达的最小的\(h\) mod \(x\)=(\(0\)~\(x-1\))都是可以抵达的层数。
\(d_i\)为能够到达的最低的 \(\bmod x = i\) 的楼层。

则有 \(i \stackrel{y}{\longrightarrow} (i+y)\bmod x\)\(i\stackrel{z}{\longrightarrow} (i+z)\bmod x\)像这样建图后,\(d_i\)就相当于 \(0→i\) 的最短路,Dijkstra 即可

code

#include <bits/stdc++.h>
using  namespace  std;

typedef long long ll;
typedef unsigned long long ull;
//#pragma GCC optimize(3)
#define pb push_back
#define is insert
#define PII pair<int,int>
#define PLL pair<ll,ll>
#define show(x) cerr<<#x<<" : "<<x<<endl;
//mt19937 mt19937random(std::chrono::system_clock::now().time_since_epoch().count());
//ll getRandom(ll l,ll r){return uniform_int_distribution<ll>(l,r)(mt19937random);}

const ll INF=0x3f3f3f3f3f3f3f3f;//2147483647;
const int N=1e5+50,M=1e4+50;
const ll mod=1e9+7;

ll d[N];int head[N];
bool vis[N];
struct node {
    int to,next;
    ll dis;
}e[N<<1];
int cnt=0;
void add_edge( int u, int v, ll d ){
    cnt++;
    e[cnt].dis=d;
    e[cnt].to=v;
    e[cnt].next=head[u];
    head[u]=cnt;
}
priority_queue<pair<ll,int>,vector<pair<ll,int>>,greater<pair<ll,int>>>q;
void dijkstra(){
    int s=1;
    memset(d,INF,sizeof(d));
    memset(vis,0,sizeof(vis));
    d[s]=1;
    q.push(make_pair(0,s));
    while(!q.empty()){
        int x=q.top().second;q.pop();
        if(vis[x])continue;
        vis[x]=1;
        for(int i=head[x];i;i=e[i].next){
            int y=e[i].to;
            if(d[y]>d[x]+e[i].dis){
                d[y]=d[x]+e[i].dis;
                if(!vis[y])q.push(make_pair(d[y],y));
            }
        }
    }
}
ll h,x,y,z;
void solve() {
    cin>>h>>x>>y>>z;
    if(x==1||y==1||z==1){
        cout<<h;
        return ;
    }
    for(int i=0;i<x;i++){
        add_edge(i,(i+y)%x,y);
        add_edge(i,(i+z)%x,z);
    }
    dijkstra();
    ll ans=0;
    for(int i=0;i<x;i++){
        //cout<<"d["<<i<<"]"<<"="<<d[i]<<endl;
        if(d[i]<=h)ans+=(h-d[i])/x+1;
    }
    cout<<ans;
}

signed main(){
    ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
    int __=1;//cin>>__;
    while(__--){
        solve();
    }
    return 0;
}
posted @ 2022-04-04 20:17  illume  阅读(53)  评论(0)    收藏  举报