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;
}
posted @ 2020-10-20 19:04  gmh77  阅读(357)  评论(0编辑  收藏  举报