8.28 Jack与Rose

题意

\(N\)个点,每个点有一个点权\(w_i\)(有正有负)

现在有两个人甲,乙,分别站在位置\(1\)与位置\(n\),此时它们身上的金钱分别为\(w_1\)\(w_n\)

在两个人行进的过程中,每经过一个点\(x\),它们身上的金钱就加上\(w_x\)

当两个人在都到达同一点时,两个人都停止移动,此时若甲身上的前比乙多,则甲胜;如果比乙少,则甲负;否则甲乙平局

现在两个人都采取最优策略,求最后甲是输,赢还是平

\(N \leq 1e4,T=10,|a_i|\leq1e4\)


解法

\(O(N^2)\)做法

这个题还算良心

有一档部分分\(N\leq 100\),能获得\(90pts\)

然而愚蠢如我当然是没有拿到的

考虑\(DP/\)记忆化搜索

设一个状态\(f[l][r][0/1]\)为甲在\(l\),乙在\(r\),对于甲\(/\)乙是胜,负还是平(用\(1,-1,0\)分别表示)

考虑对于一个点\(x\),如果两个人最终在点\(x\)相遇,我们能够很方便的判断输赢情况:

\[if \ sum[1...x] > sum[x...n] \ \ \ f[x][x][0]=1 \\ if \ sum[1...x] = sum[x...n] \ \ \ f[x][x][0]=0 \\ \ \ \ if \ sum[1...x] < sum[x...n] \ \ \ f[x][x][0]=-1 \]

这样,我们可以\(O(n)\)预处理出所有的\(f[x][x]\)

思考转移

对于一段区间\(l...r\),我们可以发现:

如果\(f[l+1][r][1]\)\(f[l][r-1][1]\)中有一个为必败态,那么\(f[l][r][0]\)必胜

因为甲为先手,它可以控制当前这个状态走向\(f[l+1][r]\)还是\(f[l][r-1]\)让乙失败,因此总能走向一个必胜态

如果\(f[l+1][r][1]\)\(f[l][r-1][1]\)均为必胜态,那么即使先手甲也无法逆转局势,只能败

否则为平局

这样转移是\(O(N^2)\)


\(O(N)\)做法

考虑\(N\)为偶数的情况:

我们可以发现,整场游戏的结局只与点\(\frac{N}{2}\)\(\frac{N}{2}+1\)有关

对于每个状态,双方都有唯一的必胜策略:

\(f(x)\)\(x\)点的状态,我们可以进行如下的讨论:

如果\(f(\frac{N}{2})=1\)或者\(f(\frac{N}{2}+1)=1\),甲必胜

对于这种情况,有如下的必胜策略:

如果\(f(\frac{N}{2})=1\),甲把乙向左移一格,此时甲与乙关于\(\frac{N}{2}\)对称

否则甲自己向右移一格,甲乙关于\(\frac{N}{2}+1\)对称

设对称点为\(x\)

接下来是乙进行移动:我们可以发现,无论乙选择哪种方式移动,甲总可以\(\lfloor\)模仿\(\rceil\)乙的操作,让每一轮操作甲乙始终关于点\(x\)对称

我们会发现最后两个人一定回来到点\(x\),并且最后一个进行操作的一定是甲

所以此时甲必胜

如果\(f(\frac{N}{2})=f(\frac{N}{2}+1)=0\),乙有唯一的必胜策略

同样,\(\lfloor\)模仿\(\rceil\)甲的操作,最后一定能使甲来到必败点

否则两者平局

对于\(N\)为奇数的情况,我们可以枚举分别判断甲进行操作\(1\)与操作\(2\)的情况:

由于甲进行一次操作以后,问题转化为偶数的情况,只不过此时的先手是乙

只要判断乙的胜负状态就可以判断甲的胜负状态了


代码

#include <cstdio>

using namespace std;

const int N = 1e5 + 10;

int t, n;
int a[N], l[N], r[N];

int main() {
	
	freopen("come.in", "r", stdin);
	freopen("come.out", "w", stdout);
	
	scanf("%d", &t);
	
	while (t--) {
		scanf("%d", &n);
		for (int i = 1; i <= n; ++i)	scanf("%d", a + i);
		
		l[0] = r[n + 1] = 0;
		for (int i = 1; i <= n; ++i)	l[i] = l[i - 1] + a[i];
		for (int i = n; i >= 1; --i)	r[i] = r[i + 1] + a[i];
		
		if (n & 1) {
			int x = n / 2, y = n / 2 + 1, z = n / 2 + 2;
			if ((l[x] > r[x] && l[y] > r[y]) || (l[y] > r[y] && l[z] > r[z]))
				puts("win");
			else if ((l[x] >= r[x] && l[y] >= r[y]) || (l[y] >= r[y] && l[z] >= r[z]))
				puts("tie");
			else 
				puts("lose");	
		} else {
			int x = n / 2, y = n / 2 + 1;
			if (l[x] > r[x] || l[y] > r[y])
				puts("win");
			else if (l[x] >= r[x] || l[y] >= r[y])
				puts("tie");
			else 
				puts("lose");
		}
		
	}
	
	return 0;
}
posted @ 2019-08-28 17:38  四季夏目天下第一  阅读(207)  评论(0编辑  收藏  举报