agc048D - Pocky Game
题目大意
n堆石子,AB两个人分别从两头开始取,每次取1~个数个,不能操作者输
n,t<=100
题解
好题
首先AB两人每次要么取一个,要么全部取完
题解并没有详细说明,这里感性证一下
如果某一方对应的那堆石子大于其余的之和,那么其必胜,否则他会弃掉这堆去抢后面的
但是如果直接弃掉的话可能会输,所以要先一个个拿来拖对面的时间,等到时机到了就直接全部丢掉
那么有dp设f[i,j,k]表示[i,j]内A先手,第i堆是k是否能获胜
发现当x能获胜时,y>=x的y也能获胜,所以改成f[i,j]表示最小获胜的a[i],g[i,j]反之
考虑A的策略,假设求的是f[i,j]
A一开始会一个个的丢,B为了让A剩下尽量少的也会一个个丢,直到a[j]等于g[i+1,j]时,如果这时B继续丢,那么A可以直接丢掉a[i]然后B就输了
所以B会在a[j]=g[i+1,j]的时候丢掉a[j],然后变成f[i,j-1]的情况,如果这时a[i]>=f[i,j-1]就可以赢
列出式子即可直接求,时间O(Tn^2)
code
#include <bits/stdc++.h>
#define fo(a,b,c) for (a=b; a<=c; a++)
#define fd(a,b,c) for (a=b; a>=c; a--)
#define min(a,b) (a<b?a:b)
#define max(a,b) (a>b?a:b)
#define ll long long
//#define file
using namespace std;
int a[101],f[101][101],g[101][101],T,n,i,j,k,l;
int main()
{
#ifdef file
freopen("d.in","r",stdin);
#endif
scanf("%d",&T);
for (;T;--T)
{
scanf("%d",&n);
fo(i,1,n) scanf("%d",&a[i]);
memset(f,127,sizeof(f));
memset(g,127,sizeof(g));
fo(i,1,n) f[i][i]=g[i][i]=1;
fo(l,2,n)
{
fo(i,1,n-l+1)
{
j=i+l-1;
if (g[i+1][j]>a[j]) f[i][j]=1;
else f[i][j]=min(a[i]+1,f[i][j-1]+(a[j]-g[i+1][j])+1);
if (f[i][j-1]>a[i]) g[i][j]=1;
else g[i][j]=min(a[j]+1,g[i+1][j]+(a[i]-f[i][j-1])+1);
}
}
printf(f[1][n]<=a[1]?"First\n":"Second\n");
}
fclose(stdin);
fclose(stdout);
return 0;
}