题解 AT_agc002_e【[AGC002E] Candy Piles】

· · 题解

AGC002E

# Description > 有 $n$ 堆石子,每堆石子有 $a_i$ 个,两人轮流操作。要么取走石子最多的一堆,要么将每堆石子取走 $1$ 个。谁取走最后 $1$ 个石子,谁就输了。假设两人都足够聪明,求先手必胜还是后手必胜。 # Solution 神仙题。 是一个经典的将博弈过程转化成网格图的模型。 考虑将 $a$ 降序排序,排在一个 $n$ 列的网格图上。初始站在 $(1,1)$ 这个位置上,令站的位置的右上部分是剩余的石子,那么两种操作相当于向上或向右走一格,谁走出去谁就输了。 记 $f_{x,y}$ 表示在 $(x,y)$ 上胜负状态,$1$ 代表先手必胜,$0$ 代表先手必败。 下面我们来证明:$f_{x,y} = f_{x+1,y+1}$。 一个状态是必败态,当且仅当它的所有后继状态都是必胜态;一个状态是必胜态,当且仅当它的后继状态存在一个必败态。 - 若 $(x,y)$ 必胜,则 $(x+1,y),(x,y+1)$ 中至少有一个必败,必败的所有后继状态都是必胜,$(x+1,y+1)$ 都是他们的后继状态,所以 $(x+1,y+1)$ 必胜。 - 若 $(x,y)$ 必败。则 $(x+1,y),(x,y+1)$ 必胜,则 $(x+2,y+1),(x+1,y+2)$ 必胜。所以 $(x+1,y+1)$ 的两个后继状态都是必胜,故 $(x+1,y+1)$ 必败。 于是我们只需要找到 $(1,1)$ 所在对角线上的最后一个点。在这个点上,之后要么一直向上,要么一直向右,两个后继状态的胜负根据剩余步数的奇偶比较好判断。就可以推出 $(1,1)$ 的状态。 时间复杂度 $O(n)$。 # code ```cpp #include<bits/stdc++.h> using namespace std; const int maxn = 1e5 + 5; int n,a[maxn],ans; bool cmp(int a,int b){return a > b;} int main() { cin >> n; for(int i = 1;i <= n;i++) cin >> a[i]; sort(a + 1,a + 1 + n,cmp); for(int i = 1;i <= n;i++) if(i + 1 > a[i + 1]) { int x = (a[i] - i + 1) & 1,y = 1; for(int j = i + 1;j <= n&&a[j] >= i;j++) y ^= 1; puts(x + y == 2 ? "Second" : "First"); return 0 ; } } ```