[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();
}
posted @ 2023-05-17 21:48  DCH233  阅读(63)  评论(0编辑  收藏  举报