[POI2014]DOO-Around the world
阿新 • • 發佈:2018-10-31
通過幾年的努力,Byteasar最終拿到了飛行員駕駛證。為了慶祝這一事實,他打算買一架飛機並且繞Byteotia星球赤道飛行一圈。但不幸的是赤道非常長所以需要中途加幾次油。現在已知赤道上面所有飛機場,所有飛機從飛機場起飛降落也可以加油。因為買飛機是個十分重大的決定,Byteasar決定尋求你的幫助。他將會讓你模擬不同的飛行路線。自然這些飛機一次能走的航程是不同的。對於每次模擬,他想要知道最少需要降落多少次(包括最後一次)。需要注意的是起點可以任意選取。
詢問<=100,飛機場<=1e6
O(1e8)可過。
斷環成鏈,複製一倍。
假設出發點都在[n+1,n+n],往左走。(即逆時針)
fa[i]表示i起點,終點在哪裡(可能不是真正的終點)
dp[i]表示,i到終點fa[i]的最少步數。
那麼,每次找到能走的最遠的j,fa[i]=fa[j],dp[i]=dp[j]+1
然後出現i-fa[i]>=n的情況,直接輸出dp[i]
原因:
首先這樣可以遍歷所有的出發點,可以遍歷到最優解。
即使fa[i]開始並不是真正的終點,但是可以在後面列舉到。
假如n+1開始的解是這樣。
我們開始列舉n+1的第一步能跳的。於是n+1的終點是:
但是上面的情況也能列舉到。由於是一個環,所以在後面的部分會列舉到這種情況。
就像這樣。
本質是同一種情況。
為什麼可以直接退出?
因為如果當前滿足的話,不存在一個更靠後的位置,使得比dp[pos]還大。
如果存在,一定會出現這種情況:
綠色這裡,藍色決策直接跨過了紅色的一段。因為紅色找的是最遠 的能跳的,所以這樣肯定是不合法的。
程式碼:
#include<bits/stdc++.h> #define ri register int using namespace std; typedef long long ll; const int N=1000000+5; int n,s; int fa[2*N],dp[2*N],sum[2*N]; int main(){ scanf("%d%d",&n,&s);int x; int mx=0; for(ri i=1;i<=n;++i){ scanf("%d",&x); mx=max(mx,x); fa[i]=i; sum[i]=sum[i-1]+x; } for(ri i=n+1;i<=n+n;++i) sum[i]=sum[i-1]+sum[i-n]-sum[i-n-1]; while(s--){ int d;scanf("%d",&d); if(d<mx) printf("NIE\n"); else for(ri i=n+1,j=1;i<=n+n;++i){ while(sum[i]-sum[j]>d) ++j; dp[i]=dp[j]+1; fa[i]=fa[j]; if(i-fa[i]>=n){ printf("%d\n",dp[i]);break; } } }return 0; }