日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

【AtCoder】【模拟】【模型转化】Camel and Oases(AGC012)

發布時間:2023/12/14 编程问答 42 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【AtCoder】【模拟】【模型转化】Camel and Oases(AGC012) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

題意:

有一個駱駝,n個綠洲遍布在數軸上,第i個綠洲的坐標為x[i],保證x[i]單增。駱駝的駝峰有體積初始值V。當駝峰的體積變為v的時候,駝峰中至多只能夠存儲v L的水。駱駝希望走完所有的綠洲,并且可以向下面這樣來走:
1.走距離d,消耗駝峰中d L的水,但是駝峰的體積不會減少。任意時候駝峰中的水的體積均不能夠為負數;
2.跳躍到任意一個位置,消耗完所有的水,并且讓駝峰的體積變為v/2。該操作在v=0的時候是不能夠進行的。
駱駝能夠在綠洲將水補滿至v。且一個綠洲可以多次訪問并進行補給。最后要求你輸出從每個位置出發,能否走完所有的綠洲。

數據范圍:

N,V<=2*1e5 ,-1e9<=x[i]<=1e9 ,且x是單增的。

思路:

首先看完題目,我們可以發現v/2這個操作是十分玄學的。這意味著只會減少log(V)+1次,就不能夠再進行任何的移動了。也說明了v的取值只會有log(V)+2種,這個數量級是很小的。
那么對于某一個v而言,駱駝能夠在一些連續的綠洲之間任意的穿梭,也就形成了一些線段。具體而言就是假如說x[i+1]-x[i]<=v,那么這兩個綠洲就是聯通的,就可以讓i和i+1處于一條線段中。我們可以發現,當v從V變換到0的時候,每一條線段的長度是在逐漸變短的,而線段的數量在逐漸增多。也就是說,v越小,駱駝的移動能力越差?,F在這個問題就變成了強迫你選擇了第一層(也就是v=V的那一層)中的某一條線段,在剩下的每一層當中,選出至多一條線段,能否存在一種方式使得最后選出來的所有的線段能夠覆蓋完所有的綠洲。
對于這個問題而言,瞬間就簡化了不少??梢远xf1[state],表示在選擇state(第i位為0表示第i層沒有選擇線段,第i位為1表示第i層選擇了一條線段)的時候,(線段從最左邊開始選)能夠覆蓋完全的最靠右的位置;定義f2[state],表示在選擇state的時候,(線段從最右邊開始選)能夠覆蓋完全的最靠左的位置。最后再掃一遍第一層中的所有的線段,表示強行選擇其中的某一條線段,然后找是否有一個state,滿足第0位不為1(第一層已經被確定了),且f1[state],f2[全集-state-1],加上這條線段,使得能夠覆蓋完所有的綠洲。
這樣子看上去似乎問題已經解決了,但是當V奇小的時候,第一層最壞可能有n條線段(一個點一條),然后就變成了\(O(n2^{log_n})=O(n^2)\)的狀態。仔細分析之后,我們可以發現,假如第一層的線段數量大于了logV+2,那么由于接下來的線段只會越來越短并且越來越多,就算是選擇第一層的所有線段也需要>logV+2條線段,而一共才能夠選擇log(V)+2條線段線段,那就顯然不可能有解了。全部輸出Impossible即可。
這樣子就變為了O(logV * n)的時間復雜度了。

代碼:

#include<cstdio> #include<cstring> #include<algorithm> #define MAXN 1000000 #define INF 2000000000 using namespace std; int n,V,x[MAXN+5]; int cnt[25];//cnt用于計算每一層所有的線段數 int l[25][MAXN+5],r[25][MAXN+5];//l表示線段的左端點,r表示的則是右端點 int f1[MAXN*5+5],f2[MAXN*5+5];//如思路中的定義 bool ans[MAXN+5];//ans記錄的是對于某一條線段的答案,不是某個綠洲的答案 void Init() {for(int i=0;i<=MAXN*5+3;i++)f1[i]=0,f2[i]=INF; } int UpFind(int id,int pos)//找l在pos+1的左邊的線段,也就是能夠向右擴展的最靠右的線段 {pos++;int p=upper_bound(l[id]+1,l[id]+cnt[id]+1,pos)-l[id];p--;if(p<=0)return pos;return max(r[id][p],pos-1); } int LowFind(int id,int pos)//找r在pos-1的右邊的線段,也就是能夠向左擴展的最靠左的線段 {pos--;int p=lower_bound(r[id]+1,r[id]+cnt[id]+1,pos)-r[id];if(p>=cnt[id]+1)return pos;return min(l[id][p],pos+1); } int main() {Init();scanf("%d %d",&n,&V);int logV=0;for(logV=0;(1<<logV)<=V;logV++);//求出來的實際上是logV+1for(int i=1;i<=n;i++)scanf("%d",&x[i]);x[n+1]=INF;x[0]=-INF;//便于操作for(int LG=0;LG<=logV;LG++){int d=V/(1<<LG);cnt[LG]=1;l[LG][1]=1;//求線段for(int i=1;i<=n;i++){r[LG][cnt[LG]]=i;if(x[i+1]-x[i]>d){cnt[LG]++;l[LG][cnt[LG]]=i+1;}}cnt[LG]--;}if(cnt[0]>logV+1)//特判{for(int i=1;i<=n;i++)printf("Impossible\n");return 0;}int all=(1<<(logV+1));f1[0]=0,f2[0]=n+1;//預處理兩個f數組for(int s=0;s<all;s+=2)for(int i=0;i<=logV;i++){if(!(s&(1<<i)))continue;f1[s]=max(f1[s],UpFind(i,f1[s-(1<<i)]));f2[s]=min(f2[s],LowFind(i,f2[s-(1<<i)]));}for(int i=1;i<=cnt[0];i++)//枚舉第一層的每一條線段{int ln=l[0][i],rn=r[0][i];for(int s1=0;s1<all;s1+=2){int s2=all-1-s1-1;int lpos=f1[s1];int rpos=f2[s2];if(lpos>=ln-1&&rpos<=rn+1)//看能否覆蓋所有的綠洲{ans[i]=true;//存的是線段的答案break;}}}int pos=1;for(int i=1;i<=n;i++){if(ans[pos]==true)printf("Possible\n");elseprintf("Impossible\n");if(x[i+1]-x[i]>V)pos++;}return 0; }

轉載于:https://www.cnblogs.com/T-Y-P-E/p/10176157.html

總結

以上是生活随笔為你收集整理的【AtCoder】【模拟】【模型转化】Camel and Oases(AGC012)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。