LG P7078 貪吃蛇
Description
草原上有 $n$條蛇,編號分別為 $1,2,\ldots,n$。初始時每條蛇有一個體力值$a_i$,我們稱編號為 $x$的蛇實力比編號為 $y$的蛇強當且僅當它們當前的體力值滿足$a_x > a_y$,或者 $a_x=a_y$且 $x > y$。
接下來這些蛇將進行決鬥,決鬥將持續若干輪,每一輪實力最強的蛇擁有選擇權,可以選擇吃或者不吃掉實力最弱的蛇:
- 如果選擇吃,那麼實力最強的蛇的體力值將減去實力最弱的蛇的體力值,實力最弱的蛇被吃掉,退出接下來的決鬥。之後開始下一輪決鬥。
- 如果選擇不吃,決鬥立刻結束。
每條蛇希望在自己不被吃的前提下在決鬥中儘可能多吃別的蛇(顯然,蛇不會選擇吃自己)。
現在假設每條蛇都足夠聰明,請你求出決鬥結束後會剩幾條蛇。
本題有多組資料,對於第一組資料,每條蛇體力會全部由輸入給出,之後的每一組資料,會相對於上一組的資料,修改一部分蛇的體力作為新的輸入。
Solution
結論:當前最強的蛇吃掉最弱的蛇之後如果沒有變成最弱的蛇(情況一),那麼它一定會選擇吃
說明:
假設當前最強的蛇叫張三,並且它吃掉最弱蛇之後不是最弱的,那麼它下一輪必不會被吃
- 如果張三吃掉最弱的之後仍然是最強的,不吃就顯然很虧,所以張三會選擇吃
- 如果張三吃掉最弱的之後不是最強的,此時的最強的蛇一定沒有剛才強,最弱的也沒有剛才弱,如果此時最強蛇選擇吃,那麼它的體力值一定比張三小,就算死也會死在張三前面,又因為它足夠聰明,不會使自己死,所以張三也不會死
- 如果張三吃掉最弱的之後不是最強的,此時的最強的蛇一定沒有剛才強,最弱的也沒有剛才弱,如果此時最強蛇選擇不吃,遊戲結束,張三顯然不死
如果吃了之後變成最弱的蛇(情況二),張三是否死將由此時的最強蛇李四決定,張三非常聰明,仔細一想,如果李四決定吃張三,那麼張三這一次就不會吃蛇使得自己成為最弱蛇,反之,如果李四不想吃,那麼張三就可以放心吃
那麼李四是否吃呢?又可以分成以上兩種情況進行討論,假如李四吃後不是最弱蛇,那麼李四會選擇吃,張三預判到李四的操作,所以選擇不吃來避免死亡
由此會發現進入第二種情況後,吃與不吃交替出現:張三預判李四,李四預判王五,王五預判趙六,……,趙六選擇吃,王五選擇不吃,李四選擇吃,張三選擇不吃
所以此時張三吃或不吃由之後這個“吃不吃”序列的長度的奇偶性決定
並且這個序列長度$\geq 2$,所以序列中必定有一個不吃,所以當遊戲進入情況二後,不會重新回到情況一,而是會再吃$0$或$1$次,然後結束
那麼做法就是模擬兩個階段
用set可以很好的維護最強蛇和最弱蛇,這種做法的時間複雜度$O(Tn\log n)$
正解是用兩個雙端佇列維護蛇的序列,使其的體力值單調,一頭強一頭弱
每次從兩個佇列尾取出最強,從某個佇列中取出最弱,不斷重複,因為新產生的蛇的體力值也具有單調性,所以不需要$\log n$資料結構維護
時間複雜度$O(Tn)$
#include<iostream> #include<utility> #include<cstdio> #include<deque> using namespace std; int T,n,a[1000005],ans,cnt; deque<pair<int,int> >q1,q2; inline int read() { int f=1,w=0; char ch=0; while(ch<'0'||ch>'9') { if(ch=='-') f=-1; ch=getchar(); } while(ch>='0'&&ch<='9') { w=(w<<1)+(w<<3)+ch-'0'; ch=getchar(); } return f*w; } int main() { T=read(); for(int i=1;i<=T;i++) { q1.clear(),q2.clear(),ans=cnt=0; if(i==1) { n=read(); for(int j=1;j<=n;j++) a[j]=read(); } else { int k=read(),x,y; for(int j=1;j<=k;j++) x=read(),y=read(),a[x]=y; } for(int i=1;i<=n;i++) q1.push_back(make_pair(a[i],i)); while(true) { if(q1.size()+q2.size()==2) { ans=1;break; } int minn=q1.front().first,maxx,id; q1.pop_front(); if(q2.empty()||q1.size()&&q1.back()>q2.back()) maxx=q1.back().first,id=q1.back().second,q1.pop_back(); else maxx=q2.back().first,id=q2.back().second,q2.pop_back(); pair<int,int>temp=make_pair(maxx-minn,id); if(temp>q1.front()) q2.push_front(temp); else { ans=q1.size()+q2.size()+2; while(true) { ++cnt; if(q1.size()+q2.size()==1) { if(!(cnt%2)) --ans; break; } int x,ID; if(q2.empty()||q1.size()&&q1.back()>q2.back()) x=q1.back().first,ID=q1.back().second,q1.pop_back(); else x=q2.back().first,ID=q2.back().second,q2.pop_back(); temp=make_pair(x-temp.first,ID); if(temp<q1.front()&&(q2.empty()||temp<q2.front())); else { if(!(cnt%2)) --ans; break; } } break; } } printf("%d\n",ans); } return 0; }貪吃蛇