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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章