[AGC048D] Pocky Game
[AGC048D] Pocky Game
这题第一印象可想到一个辛苦暴力。设 \(f_{l,r,x,y}\) 表示取到 \([l,r]\) 区间,第 \(l\) 堆石子为 \(a_l\),第 \(r\) 堆石子为 \(a_r\)。很快抛弃从这里入手的想法。
观察一下性质,不难得到一个经典结论:先手所取的石子堆中石子越多越好。这是因为取的石子个数无限制。
这样我们可以把操作按照有没有取完一堆石子分为两类,很显然每次要么取完一整堆石子,要么只取一颗石子。
手玩。感觉过程是先后手依次只取一个,到达某个临界状态后一次取完一堆。这启发我们直接按照还剩哪些石子堆来划分状态。设 \(f_{l,r}\) 表示还剩 \([l,r]\),要令先手获胜,第 \(l\) 堆石子的最小值,为转移再对称地设 \(g_{l,r}\) 表示后手的类似值。就可以 \(O(n^2)\) 做了。
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
namespace IO {
#define isdigit(x) (x >= '0' && x <= '9')
template<typename T>
inline void read(T &x) {
x = 0; char ch = getchar(); int f = 0;
for(; !isdigit(ch); ch = getchar()) if(ch == '-') f = 1;
for(; isdigit(ch); ch = getchar()) x = x * 10 + ch - '0';
if(f) x = -x;
}
template<typename T>
inline void write(T x) {
if(x < 0) putchar('-'), x = -x;
if(x > 9) write(x / 10);
putchar(x % 10 + '0');
}
#undef isdigit
}
using namespace IO;
const int N = 110;
LL n, a[N];
LL f[N][N], g[N][N];
void solve() {
read(n);
for(int i = 1; i <= n; ++i)
read(a[i]), f[i][i] = g[i][i] = 1;
for(int i = 2; i <= n; ++i)
for(int l = 1; l + i - 1 <= n; ++l) {
int r = l + i - 1;
f[l][r] = (a[r] < g[l + 1][r]) ? 1 : (f[l][r - 1] + a[r] - g[l + 1][r] + 1);
g[l][r] = (a[l] < f[l][r - 1]) ? 1 : (g[l + 1][r] + a[l] - f[l][r - 1] + 1);
}
puts(a[1] >= f[1][n] ? "First" : "Second");
}
int main() {
int T; read(T);
while(T--) solve();
}