Codeforces gym 102823J. Stone Game 题解
题目大意
Alice 和 Bob 取石子,每一回合只能从某一堆上取一个,并且任何时候相邻两堆石子个数不能相同,不能再取得人失败。Alice 先手,问二人谁必胜?
题解
我们来想最终极限不能取的状态应该是什么样子的。例如有一个部分最初为 \(2,3,5,7,8\),我们发现取法是把这样的上升序列取成连续序列,比如刚才的部分最终的状态一定是 \(0,1,2,3,4\)(从左边的小的石子堆取,取完之后向右继续),此时这一部分不能再被任何人取,可视为最终状态。
所以我们可以对原数组进行处理,把类似这样的上升序列转换为其最终的状态(代码中的 \(b[i]\) 即代表 \(i\) 位置最终的状态),由于下降序列同理,所以从左往右和从右往左各自来一遍,两次 \(b[i]\) 取最大的限制,然后得到最终状态后,计算初始到最终状态的石子数,若为奇数则先手 Alice 胜。
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58
| #include <cstdio> #include <cctype> #include <algorithm> #include <cstring> #include <iostream> #include <cassert> #include <cmath> using namespace std; typedef long long ll; template <typename _Tp> void read(_Tp &a, char c = 0, int f = 1) { for(c = getchar(); !isdigit(c); c = getchar()) if(c == '-') f = -1; for(a = 0; isdigit(c); a = a * 10 + c - '0', c = getchar()); a *= f; } template <typename _Tp> void write(_Tp a) { if(a < 0) putchar('-'), a = -a; if(a > 9) write(a / 10); putchar(a % 10 + '0'); }
const int N = 1e5 + 5; ll n, a[N], b[N];
void init() { memset(b, 0, sizeof b); }
int main() { int T; read(T); for(int _T = 1; _T <= T; _T++) { init(); read(n); ll x = 0; for(int i = 1; i <= n; i++) read(a[i]); ll tot = 0; for(int i = 2; i <= n; i++) { if(a[i] > a[i - 1]) tot++; else tot = 0; b[i] = max(b[i], tot); } tot = 0; for(int i = n - 1; i >= 1; i--) { if(a[i] > a[i + 1]) tot++; else tot = 0; b[i] = max(b[i], tot); } for(int i = 1; i <= n; i++) { x += a[i] - b[i]; } printf("Case %d: %s\n", _T, x % 2 == 1 ? "Alice" : "Bob"); } return 0; }
|