LG P7078 贪吃蛇

Description

草原上有 $n$ 条蛇,编号分别为 $1,2,ldots,n$。初始时每条蛇有一个体力值$a_i$,我们称编号为 $x$ 的蛇实力比编号为 $y$ 的蛇强当且仅当它们当前的体力值满足$a_x > a_y$,或者 $a_x=a_y$ 且 $x > y$

接下来这些蛇将进行决斗,决斗将持续若干轮,每一轮实力最强的蛇拥有选择权,可以选择吃或者不吃掉实力最弱的蛇:

  1. 如果选择吃,那么实力最强的蛇的体力值将减去实力最弱的蛇的体力值,实力最弱的蛇被吃掉,退出接下来的决斗。之后开始下一轮决斗。
  2. 如果选择不吃,决斗立刻结束。

每条蛇希望在自己不被吃的前提下在决斗中尽可能多吃别的蛇(显然,蛇不会选择吃自己)。

现在假设每条蛇都足够聪明,请你求出决斗结束后会剩几条蛇。

本题有多组数据,对于第一组数据,每条蛇体力会全部由输入给出,之后的每一组数据,会相对于上一组的数据,修改一部分蛇的体力作为新的输入。

Solution

结论:当前最强的蛇吃掉最弱的蛇之后如果没有变成最弱的蛇(情况一),那么它一定会选择吃

说明:

假设当前最强的蛇叫张三,并且它吃掉最弱蛇之后不是最弱的,那么它下一轮必不会被吃

  • 如果张三吃掉最弱的之后仍然是最强的,不吃就显然很亏,所以张三会选择吃
  • 如果张三吃掉最弱的之后不是最强的,此时的最强的蛇一定没有刚才强,最弱的也没有刚才弱,如果此时最强蛇选择吃,那么它的体力值一定比张三小,就算死也会死在张三前面,又因为它足够聪明,不会使自己死,所以张三也不会死
  • 如果张三吃掉最弱的之后不是最强的,此时的最强的蛇一定没有刚才强,最弱的也没有刚才弱,如果此时最强蛇选择不吃,游戏结束,张三显然不死

如果吃了之后变成最弱的蛇(情况二),张三是否死将由此时的最强蛇李四决定,张三非常聪明,仔细一想,如果李四决定吃张三,那么张三这一次就不会吃蛇使得自己成为最弱蛇,反之,如果李四不想吃,那么张三就可以放心吃

那么李四是否吃呢?又可以分成以上两种情况进行讨论,假如李四吃后不是最弱蛇,那么李四会选择吃,张三预判到李四的操作,所以选择不吃来避免死亡

由此会发现进入第二种情况后,吃与不吃交替出现:张三预判李四,李四预判王五,王五预判赵六,……,赵六选择吃,王五选择不吃,李四选择吃,张三选择不吃

所以此时张三吃或不吃由之后这个“吃不吃”序列的长度的奇偶性决定

并且这个序列长度$geq 2$,所以序列中必定有一个不吃,所以当游戏进入情况二后,不会重新回到情况一,而是会再吃$0$或$1$次,然后结束

那么做法就是模拟两个阶段

用set可以很好的维护最强蛇和最弱蛇,这种做法的时间复杂度$O(Tnlog 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
",ans);
    }
    return 0;
}
贪吃蛇
原文地址:https://www.cnblogs.com/JDFZ-ZZ/p/13968148.html