[洛谷P3403] 跳樓機
阿新 • • 發佈:2020-08-23
問題描述
Srwudi 的家是一幢 h 層的摩天大樓。由於前來學習的蒟蒻越來越多,srwudi 改造了一個跳樓機,使得訪客可以更方便的上樓。
經過改造,srwudi 的跳樓機可以採用以下四種方式移動:
- 向上移動 x 層;
- 向上移動 y 層;
- 向上移動 z 層;
- 回到第一層。
一個月黑風高的大中午,DJL 來到了 srwudi 的家,現在他在 srwudi 家的第一層,碰巧跳樓機也在第一層。DJL 想知道,他可以乘坐跳樓機前往的樓層數。
輸入格式
第一行一個整數 h,表示摩天大樓的層數。
第二行三個正整數,分別表示題目中的 x, y, z。
輸出格式
一行一個整數,表示 DJL 可以到達的樓層數。
樣例輸入
15
4 7 9
樣例輸出
9
資料範圍
\(h\le 2^63-1,x,y,z\le 10^5\)
解析
不妨只考慮第二和第三兩種操作,設 \(f_i\) 表示僅用二三操作能夠到達的 \(\bmod x=1\) 的最小樓層。那麼我們可以利用 \(f_i\) 將屬於 \(x\) 剩餘系的樓層到達。至於怎麼求,我們有一個顯然的DP:
\[f_{(i+y)\bmod x}=f_i+y\\f_{(i+z)\bmod x}=f_i+z \]
但範圍太大。我們可以把這個轉化成最短路就能保證複雜度了。
程式碼
#include <iostream> #include <cstdio> #include <cstring> #include <queue> #define N 100002 #define M 1000002 #define int long long using namespace std; int head[N],ver[M*2],nxt[M*2],edge[M*2],l; int n,x,y,z,i,dis[N]; void insert(int x,int y,int z) { l++; ver[l]=y; edge[l]=z; nxt[l]=head[x]; head[x]=l; } void Dijkstra() { priority_queue<pair<int,int> > q; memset(dis,0x3f,sizeof(dis)); q.push(make_pair(-1,1)); dis[1]=1; while(!q.empty()){ int x=q.top().second,d=-q.top().first; q.pop(); if(d!=dis[x]) continue; for(int i=head[x];i;i=nxt[i]){ int y=ver[i]; if(dis[y]>dis[x]+edge[i]){ dis[y]=dis[x]+edge[i]; q.push(make_pair(-dis[y],y)); } } } } signed main() { scanf("%lld%lld%lld%lld",&n,&x,&y,&z); if(x==1||y==1||z==1){ printf("%lld\n",n); return 0; } for(i=0;i<x;i++) insert(i,(i+y)%x,y),insert(i,(i+z)%x,z); Dijkstra(); int ans=0; for(i=0;i<x;i++){ if(dis[i]<=n) ans+=(n-dis[i])/x+1; } printf("%lld\n",ans); return 0; }