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; }