[AGC048D] Pocky Game
一、题目
二、解法
由于这是一个不平等博弈,我称左边的玩家为"左手",右边的玩家为"右手"
通过手玩可以给出一些合理的猜测:当前人正在拿的那一堆的石子数越多越优。证明方法同样简洁:对于石子数更少的必胜方案,我们只需要把最后一步从取最后一个石子改成取走整堆石子,其他地方都不变即可。
那么可以根据这个性质来 ,设 表示 的石子都是原序列中的整堆,左手必胜需要最小的石子数是多少;再设 表示 的石子都是原序列中的整堆,右手必胜需要的最小石子数是多少,下面我们讨论 的转移, 的转移可以类似地推导出来。
首先考虑有两个显然的偏序关系(都是根据定义而来的):
- ,若此时左手执,则左手取完这堆石子之后必胜。
- ,若此时右手执,则右手取完这堆石子之后必胜。
第一种转移:若 ,那么
第二种转移:若 ,右手一定会在 的时候取完这堆石子,那么胜利的条件是可以逼迫后手进行完拉锯战,并且右手取完石子之后还可以满足子问题的胜利条件:
用区间 的方式转移即可,最后判断 和 的关系即可得出答案,时间复杂度
三、总结
博弈论的新奇结论:考虑是否存在某一个分界点,使得它一边是 状态,一边是 状态。
博弈论中多考虑一些必胜态与必败态也许有助于思考(怎么感觉像是废话啊)
#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();
}
分类:
其他-----博弈论
, dp-----区间dp
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
2021-01-11 [湖北省队互测2014] 一个人的数论