zoukankan      html  css  js  c++  java
  • agc048D

    题目大意

    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
    ":"Second
    ");
    	}
    	
    	fclose(stdin);
    	fclose(stdout);
    	return 0;
    }
    
  • 相关阅读:
    Oracle第一课
    Web前端试题
    E
    Kingdom of Black and White
    D. Let's Go Hiking
    2021牛客寒假 第一场
    Codeforces Round #691 (Div. 2)
    CF1461D
    CF1461B
    浙财16th校赛 F因子
  • 原文地址:https://www.cnblogs.com/gmh77/p/13848293.html
Copyright © 2011-2022 走看看