动态规划、组合数学、博弈论

首先注意到平局只有一种可能:第一轮 A 先手拿到 $n-1$,B 后手拿到 $n$;第二轮 B 先手拿到 $n-3$,A 后手拿到 $n-2$,以此类推。

其次,如果第一轮 A 先手拿到 $n$ 那么显然胜利,如果 $n$ 在 B 手上,那么 A 需要让 B 在第一轮出掉 $n$,否则将会倒在第二轮。那么 A 的最优策略是出手中最小的比 B 第二大的牌更大的牌。

考虑 A 没有拿到 $n$ 的情况,此时应当让 B 在第一轮出 $n$,注意到对 A 而言如果有多张牌能让 B 出 $n$,那么这些牌的大小关系是无所谓的,因为 B 除了 ${n}$ 以外没有比这些牌更大的牌了。于是第一轮只有三种情况。

  • A 拿到 $n$ 杀死比赛。有 $C_{n-1}^{\frac{n}{2}}$ 种情况。
  • A 没有逼出 B 的 $n$,下一轮 B 杀死比赛。当且仅当 B 同时拿到 $n$ 和 $n-1$,有 $C_{n-2}^{\frac{n}{2}}$ 种情况。
  • A 逼出 B 的 $n$。由上一种情况可以发现此时 A 一定拿到 $n-1$,且所有能逼出 $n$ 的牌等价,所以可以认为 A 打出了 $n-1$ 来迫使 B 出 $n$。然后问题转化到 $n-2$ 张牌的情况。

预处理答案,单组数据时间复杂度 $O(1)$。

没搞懂为啥 $n \leq 60$,也不知道为啥难度评这么低,估计有基于 $n$ 的值不超过 $60$ 的高妙简单做法。

constexpr int mod=998'244'353;
Combination<Mint<mod>,60,mod> C;
Mint<mod> a[35],b[35];
int T,n;
int main(){
    ios::sync_with_stdio(0);
    a[1]=1,b[1]=0;
    for(int i=2;i<=30;i++){
        a[i]=C(i*2-1,i)+b[i-1];
        b[i]=C(i*2-2,i)+a[i-1];
    }
    cin>>T;
    while(T--){
        cin>>n;
        cout<<a[n>>1]<<' '<<b[n>>1]<<' '<<1<<'\n';
    }
    return 0;
}
最后修改:2024 年 08 月 07 日
如果觉得我的文章对你有用,请随意赞赏