1 条题解

  • 0
    @ 2025-8-24 21:39:30

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar yybyyb
    **

    搬运于2025-08-24 21:39:30,当前版本为作者最后更新于2018-10-08 19:42:57,作者可能在搬运后再次修改,您可在原文处查看最新版

    自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多

    以下是正文


    神仙题.jpg。ZJOIZJOI是真的神仙。
    发现SGSG函数等东西完全找不到规律,无奈只能翻题解。

    首先设L[i][j]L[i][j]表示在[i,j][i,j]这一段区间的左侧放上一堆数量为L[i][j]L[i][j]的石子后,先手必败。同理定义R[i][j]R[i][j]表示右侧。

    首先我们可以证明L[i][j]L[i][j]唯一,假设存在两个L[i][j]L[i][j],显然较大的那个可以通过一步转移转移到较小的那个,所以不合法。因此L[i][j]L[i][j]唯一。

    接下来考虑如何证明L[i][j]L[i][j]一定存在。假设L[i][j]L[i][j]不存在,那么对于这段区间而言,在左边加上任意一堆石子先手都必胜,既然先手必胜意味着先手进行一步操作之后可以到达一个必败态,这里分情况讨论。假设先手拿的是最左边的一堆石子,因为不存在L[i][j]L[i][j],所以只要拿了左边的石子之后,当前局面都是必胜态,所以不可能拿左边的石子。那么只能拿右边的石子,那么无论右边拿了一定量之后,无论左边添加了多少,都是一个必败态,那么此时后手在左侧随便拿走一定数量,这个状态也还是一个必败态,显然也不成立。因此L[i][j]L[i][j]必定存在。

    综上,我们知道了L[i][j]L[i][j]一定存在并且唯一,而L[][],R[][]L[][],R[][]显然是对称的,因此R[i][j]R[i][j]也满足上述性质。

    现在考虑如何求解L[i][j]L[i][j],R[i][j]R[i][j]同理。首先边界情况显然,L[i][i]=a[i]L[i][i]=a[i],因为只剩下两堆一模一样的情况的时候,后手只需要模仿先手的行动对称执行就好了,这样子一定不会输,即先手必败。

    接下来来大力分类讨论,为了方便,设L=L[i][j1],R=R[i][j1],x=a[j]L=L[i][j-1],R=R[i][j-1],x=a[j]

    • x=Rx=R

      这种情况下显然只需要直接把a[j]a[j]放进去就好了,即这个区间本身就是一个必败态。所以L[i][j]=0L[i][j]=0

    • x<L,x<Rx<L,x<R

      这种情况下L[i][j]=xL[i][j]=x。这种情况下最靠左的L[i][j]L[i][j]x=a[j]x=a[j]是相同的,意味着先手无论怎么取,后手显然可以学着它的方法取,也就意味着左右两堆中显然必然会先拿完一堆,此时后手学着拿的那一堆的石子数一定也是小于L,RL,R的。假设先手先拿完了最靠右的一堆,即剩下了[i,j1][i,j-1],因为L[i][j1]L[i][j-1]表示的是在这一段区间最左侧加入一个L[i][j1]L[i][j-1]的堆,无论先手怎么取先手都是必败的,那么我们等价的认为先手取走了这一堆的一部分,显然后手是必胜的。假如先手先取完的是最左的一堆,同理,R[i][j1]R[i][j-1]的含义是在最右侧加入了一堆,而a[j]<R[i][j1]a[j]<R[i][j-1],我们还是可以等价的认为先手在这一堆中取走了若干石子,而这个状态对于先手而言是必败状态,因此显然后手必胜。

    • R<x<LR<x<L

      这种情况下L[i][j]=x1L[i][j]=x-1。这样子考虑,假设先手先拿了左边这一堆,那么假设还剩下了zz个石子,如果z<Rz<R,后手把右侧的那一堆也给拿成zz就变成了上面的情况。如果zRz\ge R,那么后手把最后那一堆拿成z+1z+1,于是又回到了这种情况,相当于这种情况递归处理。如果先手先拿的是右侧的这一堆,还是一样的,假设把它拿成了zz,如果z<Rz<R,同上可以变成x<L,x<Rx<L,x<R的情况;如果y=Ry=R,直接把左边拿完,就变成了R[i][j1]R[i][j-1]的定义了,先手必败;如果z>Rz>R,把左边那堆变成z1z-1,同样递归处理。

    • L<x<RL<x<R

      分析同上,L[i][j]=x+1L[i][j]=x+1

    • x>L,x>Rx>L,x>R

      L[i][j]=xL[i][j]=x。还是一样的,假设先手把其中一堆拿成了zz。如果z>L,Rz>L,R,跟着先手拿成一样多的石子则又回到了这种情况。如果z<L,Rz<L,R,则可以回到情况x<L,Rx<L,R。否则的话对应着把另外一堆变成z+1z+1或者z1z-1,对应着L<x<RL<x<RR<x<LR<x<L两种情况。

    R[][]R[][]L[][]L[][]是对称的,类似的求解即可。

    那么最终只需要判断L[2][n]L[2][n]a[1]a[1]是否相等即可判断胜负情况。

    代码有点丑

    #include<iostream>
    #include<cstdio>
    using namespace std;
    #define MAX 1010
    inline int read()
    {
    	int x=0;bool t=false;char ch=getchar();
    	while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
    	if(ch=='-')t=true,ch=getchar();
    	while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
    	return t?-x:x;
    }
    int n,a[MAX],L[MAX][MAX],R[MAX][MAX];
    int main()
    {
    	int T=read();
    	while(T--)
    	{
    		n=read();
    		for(int i=1;i<=n;++i)a[i]=read();
    		for(int i=1;i<=n;++i)L[i][i]=R[i][i]=a[i];
    		for(int len=2;len<=n;++len)
    			for(int i=1,j=i+len-1;j<=n;++i,++j)
    			{
    				int x=a[j],l=L[i][j-1],r=R[i][j-1];
    				if(x==r)L[i][j]=0;
    				else if((x>l&&x>r)||(x<l&&x<r))L[i][j]=x;
    				else if(r<x&&x<l)L[i][j]=x-1;
    				else L[i][j]=x+1;
    				x=a[i],l=L[i+1][j],r=R[i+1][j];
    				if(x==l)R[i][j]=0;
    				else if((x>l&&x>r)||(x<l&&x<r))R[i][j]=x;
    				else if(r<x&&x<l)R[i][j]=x+1;
    				else R[i][j]=x-1;
    			}
    		puts(a[1]==L[2][n]?"0":"1");
    	}
    }
    
    • 1

    信息

    ID
    1635
    时间
    1000ms
    内存
    128MiB
    难度
    6
    标签
    递交数
    0
    已通过
    0
    上传者