其他分享
首页 > 其他分享> > BZOJ 1413: [ZJOI2009]取石子游戏 博弈+Dp

BZOJ 1413: [ZJOI2009]取石子游戏 博弈+Dp

作者:互联网

title

BZOJ 1413
Description

在研究过Nim游戏及各种变种之后,Orez又发现了一种全新的取石子游戏,这个游戏是这样的: 有n堆石子,将这n堆石子摆成一排。游戏由两个人进行,两人轮流操作,每次操作者都可以从最左或最右的一堆中取出若干颗石子,可以将那一堆全部取掉,但不能不取,不能操作的人就输了。 Orez问:对于任意给出一个初始一个局面,是否存在先手必胜策略。

Input

文件的第一行为一个整数T,表示有 T组测试数据。对于每组测试数据,第一行为一个整数n,表示有n堆石子;第二行为n个整数ai,依次表示每堆石子的数目。

Output

对于每组测试数据仅输出一个整数0或1。其中1表示有先手必胜策略,0表示没有。

Sample Input

1
4
3 1 9 4

Sample Output

0
数据范围
对于30%的数据 n≤5 ai≤105
对于100%的数据 T≤10 n≤1000 每堆的石子数目≤109

analysis

首先我们令 :
L[i][j]L[i][j]L[i][j] 表示当前 [i,j][i,j][i,j] 区间左侧放置 L[i,j]L[i,j]L[i,j] 数量的石子后先手必败;
R[i][j]R[i][j]R[i][j] 表示当前 [i,j][i,j][i,j] 区间右侧放置 R[i,j]R[i,j]R[i,j] 数量的石子后先手必败。

那么最后我们只要判断 a[1]a[1]a[1] 是否等于 L[2,n]L[2,n]L[2,n] 或者 a[n]a[n]a[n] 是否等于 R[1,n1]R[1,n−1]R[1,n−1] 即可。

唯一性
考虑证明 L[i][j]L[i][j]L[i][j] 和 R[i][j]R[i][j]R[i][j] 的唯一性,发现我们只需要证明一个成立即可。

假设 L[i][j]L[i][j]L[i][j] 存在两个,那么我们先让 [i,j][i,j][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][j1],R[i][j1],a[j]L[i][j−1],R[i][j−1],a[j]L[i][j−1],R[i][j−1],a[j] 来处理,我们令 L=L[i][j1],R=R[i][j1],x=a[j]L=L[i][j−1],R=R[i][j−1],x=a[j]L=L[i][j−1],R=R[i][j−1],x=a[j]。

最后,yyb OrzOrzOrz。

code

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e3+10;

char buf[1<<15],*fs,*ft;
inline char getc() { return (ft==fs&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),ft==fs))?0:*fs++; }
template<typename T>inline void read(T &x)
{
    x=0;
    T f=1, ch=getchar();
    while (!isdigit(ch) && ch^'-') ch=getchar();
    if (ch=='-') f=-1, ch=getchar();
    while (isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48), ch=getchar();
    x*=f;
}

char Out[1<<24],*fe=Out;
inline void flush() { fwrite(Out,1,fe-Out,stdout); fe=Out; }
template<typename T>inline void write(T x)
{
    if (!x) *fe++=48;
    if (x<0) *fe++='-', x=-x;
    T num=0, ch[20];
    while (x) ch[++num]=x%10+48, x/=10;
    while (num) *fe++=ch[num--];
    *fe++='\n';
}

int a[maxn],l[maxn][maxn],r[maxn][maxn];
int main()
{
	int T;read(T);
	while (T--)
	{
		int n;read(n);
		for (int i=1; i<=n; ++i) read(a[i]),l[i][i]=r[i][i]=a[i];
		for (int len=1; len<=n; ++len)
			for (int i=1; i+len<=n; ++i)
			{
				int j=i+len;
				int L=l[i][j-1],R=r[i][j-1],z=a[j];
				if (R==z) l[i][j]=0;
				else if (L>z && R>z) l[i][j]=z;
				else if (L<=z && R>z) l[i][j]=z+1;
				else if (L>z && R<z) l[i][j]=z-1;
				else l[i][j]=z;
				L=l[i+1][j],R=r[i+1][j],z=a[i];
				if (R==z) r[i][j]=0;
				else if (L>z && R>z) r[i][j]=z;
				else if (L<=z && R>z) r[i][j]=z+1;
				else if (L>z && R<z) r[i][j]=z-1;
				else r[i][j]=z;
			}
		write(a[1]==l[2][n]?0:1);
	}
	flush();
	return 0;
}

标签:ch,左边,石子,ZJOI2009,先手,lt,LLL,1413,Dp
来源: https://blog.csdn.net/huashuimu2003/article/details/97817529