• [AGC048D] Pocky Game


    一、题目

    点此看题

    二、解法

    由于这是一个不平等博弈,我称左边的玩家为"左手",右边的玩家为"右手"

    通过手玩可以给出一些合理的猜测:当前人正在拿的那一堆的石子数越多越优。证明方法同样简洁:对于石子数更少的必胜方案,我们只需要把最后一步从取最后一个石子改成取走整堆石子,其他地方都不变即可。

    那么可以根据这个性质来 \(dp\),设 \(F[l][r]\) 表示 \((l,r]\) 的石子都是原序列中的整堆,左手必胜需要最小的石子数是多少;再设 \(G[l][r]\) 表示 \([l,r)\) 的石子都是原序列中的整堆,右手必胜需要的最小石子数是多少,下面我们讨论 \(F[l][r]\) 的转移,\(G[l][r]\) 的转移可以类似地推导出来。

    首先考虑有两个显然的偏序关系(都是根据定义而来的):

    • \(G[l+1][r]>a_r\),若此时左手执,则左手取完这堆石子之后必胜。
    • \(F[l][r-1]>a_l\),若此时右手执,则右手取完这堆石子之后必胜。

    第一种转移:若 \(G[l+1][r]>a_r\),那么 \(F[l][r]=1\)

    第二种转移:若 \(G[l+1][r]\leq a_r\),右手一定会在 \(G[l+1][r]=a_r\) 的时候取完这堆石子,那么胜利的条件是可以逼迫后手进行完拉锯战,并且右手取完石子之后还可以满足子问题的胜利条件:

    \[F[l][r]=(a_r-G[l+1][r]+1)+F[l][r-1] \]

    用区间 \(dp\) 的方式转移即可,最后判断 \(F[1][n]\)\(a_1\) 的关系即可得出答案,时间复杂度 \(O(n^2)\)

    三、总结

    博弈论的新奇结论:考虑是否存在某一个分界点,使得它一边是 \(N\) 状态,一边是 \(P\) 状态。

    博弈论中多考虑一些必胜态与必败态也许有助于思考(怎么感觉像是废话啊

    #include <cstdio>
    const int M = 105;
    #define int long long
    int read()
    {
    	int x=0,f=1;char c;
    	while((c=getchar())<'0' || c>'9') {if(c=='-') f=-1;}
    	while(c>='0' && c<='9') {x=(x<<3)+(x<<1)+(c^48);c=getchar();}
    	return x*f;
    }
    int T,n,a[M],F[M][M],G[M][M];
    void work()
    {
    	n=read();
    	for(int i=1;i<=n;i++)
    		a[i]=read(),F[i][i]=G[i][i]=1;
    	for(int l=n;l>=1;l--)
    		for(int r=l+1;r<=n;r++)
    		{
    			//transform of F
    			if(G[l+1][r]>a[r]) F[l][r]=1;
    			else F[l][r]=(a[r]-G[l+1][r]+1)+F[l][r-1];
    			//transform of G
    			if(F[l][r-1]>a[l]) G[l][r]=1;
    			else G[l][r]=(a[l]-F[l][r-1]+1)+G[l+1][r];
    		}
    	puts(F[1][n]<=a[1]?"First":"Second");
    }
    signed main()
    {
    	T=read();
    	while(T--) work();
    }
    
  • 相关阅读:
    内联函数(inline function)
    被extern "C" 修饰后按照C语言编译
    函数重载-name mangling或mame decoration技术-看看反汇编
    cin、cout
    下载visual studio 环境搭建
    配置共享文件夹
    EFS加密文件系统
    十二、字符串(1)
    十五、文件
    十一、指针
  • 原文地址:https://www.cnblogs.com/C202044zxy/p/15788800.html
Copyright © 2020-2023  润新知