Stone Game

题目链接
题目描述

Alice and Bob are always playing game! The game today is about taking out stone from the stone piles in turn.
There are n piles of stones, and the i-th pile contains A[i] stones.
As the number of stones in each pile differs from its neighbor’s, they determine to take out exactly one stone from one of them in one turn without breaking that property. Alice goes first.
The player who cannot take stone will lose the game.
Now you have to determine the winner given n numbers representing the piles, if they both play optimally.
You should notice that even a pile of 0 stone is still regarded as a pile!

输入

The first line of input file contains an integer T (1≤T≤100), describing the number of test cases.
Then there are 2×T lines, with every two lines representing a test case.
The first line of each test case contains only one integer n (1≤n≤105) as described above.
The second line of that contains exactly n numbers, representing the number of stone(s) in a pile in order.
All these numbers are ranging in [0,109].
It is guaranteed that the sum of n in all cases does not exceed 106.

输出

You should output exactly T lines.
For each test case, print Case d: (d represents the order of the test case) first, then print the name of winner, Alice or Bob .

样例输入
复制样例数据

2
2
1 3
3
1 3 1
样例输出

Case 1: Alice
Case 2: Bob

提示

Sample 1:
There is a possible stone-taking sequence: (1,3)-> (1,2)-> (0,2)-> (0,1)
Here is an invalid sequence: (1,3)-> (1,2)-> (1,1)-> (0,1). Though it has the same result as the first sequence, it breaks that property “the number of stones in each pile differs from its neighbor’s”.

【题意】

n堆石子,保证相邻两堆不等。A和B玩游戏,轮流从这n堆中,任意拿走一颗石子,但需要保证拿走第i堆的一颗石子后,第i堆的石子不能和他相邻堆相等。谁无法拿石子时,谁就输。问谁能赢?
思路:

如果中间的石头比左右两堆都少,那么它一定可以被拿至0,即它是这些堆石头的极小值;
如果它比左右两堆都多,那么它一定保持大于左右两堆的状态,则它下限为max(a[L],a[R])+1,这其实就是极大值,但是在改变极大值的时候不能直接改为多少,而是要在两边石头数量最大的基础上加1。
如果两边是一多一少,那么少的那堆的个数+1是第i堆的下限。
我们应该按个数从少到多处理每一堆,使每一堆的个数变成其下限。计拿走的石子总个数为sum,若sum为奇数则Alice胜,反之为则Bob胜。

注意:这道题在处理的时候,一定要注意a这个数组,a数组中的元素的大小关系是一定不会发生任何改变的。所以在改变a数组的元素值时,一定要注意!!!如果是极小值点所在的位置,则直接改变为0就可。其余的我们由少到多一次加1。在加1的时候要注意条件的把握,极大值所在的地方我们在修改的时候要换条件,不能直接在某一个元素的基础上直接加1!!!

代码如下:

#include<stdio.h>
#include<iostream>

using namespace std;

#define LL long long int 
#define INF 100000

const int N = 1e6+5;
int a[N],c[N];//a数组保存每堆石头原始的数量,b数组保存的是每堆石头最后的数量
int t, n,case_num=1;
LL sum;//sum用来装我能移动多少个石头来判定是先手赢还是后手赢

int main() {
	cin >> t;
	while (t--) {
		sum = 0ll;
		cin >> n;
		for (int i = 1; i <= n; i++) {
			scanf("%d",&a[i]);
			sum += a[i];
		}
		cout << "Case " << case_num++ << ": ";
		if (n == 1) {
			if (sum % 2 == 1) cout << "Alice" << endl;
			else cout << "Bob" << endl;
			continue;
		}
		int count_num = 0;
		for (int i = 2; i < n; i++) {
			if ((a[i] < a[i - 1]) && (a[i] < a[i + 1])) {
				c[count_num++] = i;
			}
		}
		a[0] = -1;
		for (int i = 1; i < n && a[i] < a[i + 1]; i++) {
			a[i] = a[i - 1] + 1;
		}
		a[n + 1] = -1;
		for (int i = n; i > 1 && a[i] < a[i - 1]; i--) {
			a[i] = a[i + 1] + 1;
		}
		//重点
		for (int i = 0; i <count_num; i++) {
			a[c[i]] = 0;
			for (int j = c[i] + 1; j< n && a[j] < a[j + 1]; j++) {
				a[j] = a[j - 1] + 1;
			}
			for (int j = c[i] - 1; j > 1 && a[j] < a[j - 1]; j--) {
				a[j] = a[j + 1] + 1;
			}
		}//重点
		for (int i = 1; i <= n; i++)
		{
			if (i == 1 && a[1] > a[2]) {
				a[1] = a[2] + 1;
			}
			else if (i == n && a[n] > a[n - 1]) {
				a[n] = a[n - 1] + 1;
			}
			else if (a[i - 1]<a[i] && a[i]>a[i + 1])
				a[i] = max(a[i - 1], a[i + 1]) + 1;
		}
		for (int i = 1; i <= n; i++) {
			sum -= a[i];
		}
		if (sum % 2) cout << "Alice" << endl;
		else cout << "Bob" << endl;
	}
	return 0;
}

PS:这道题在第二个测试点处很容易超时,要注意!!!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小编程员

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值