codeforces 博弈 Card Game

题目描述:

 题目大意: 有1 - n恰好 n 张牌,平均分配给Alex 和Boris两个人。在一回合中,先手出牌,如果对方没有可以出的牌,则先手胜。如果可以出,那出完后这个人继续出。如果对手打不起牌,那么就由对方出牌。问有多少种分配可以使得先手必胜,先手必输以及先手以及平手。

解题思路

        假如先手有 n 这张牌,那么先手必胜。

        如果先手没有 n ,那么如果 n - 1 也在对方手中,那么先手必败。那么先手假设没有 n ,他如果要赢的话他就必须要有 n - 1。

        即  Alex : n - 1        Boris : n

        但如果 Boris 还有 n - 2 这张牌的话,那么Boris 也是必赢的,因为如果先手出 n - 1,那么后手出 n,再出n-2带走比赛,如果先手出小于n-2的牌,那么后手先出n-2,然后出n带走比赛。依次类推,平局的方式只有一种。

        如果 Alex 没有 n 但是想赢。

        Alex : n - 1  ,  n - 2           Boris : n

        这种情况是可以赢的。 Alex 先用 n - 1 逼出对手的 n , 然后对手再出牌后Alex 出 n-2。也就是说,Alex 先要用第二小的数逼出 Boris 最大的数。

        Alex : n - 1 ,  n - 3     n- 4        Boris: n  n - 2

        上述情况也是这样,先逼出 Boris 最大的牌,才可以取胜。

        假如我们定义 dp[i] 表示 有 2*i 张牌,使得先手必胜的分配数,那么第一种可能是先手有最大的那个数,然后其他的就随便分配。也就是 C(2*i - 1, i - 1)这个组合数。 

        假如先手没有 2*i 这张牌,那么先手必须要有 2*i - 1 这张牌,然后根据上面的推理,一个回合后逼出对手最大的那张牌,随后对方先手,剩下的牌只有 2*i - 2张,也就是这时候的先手必胜,转换成了对方先手但只有2*i - 2张牌时必输的情况。

        而我们知道,无论牌多少张,只有一种分配方式是平手的,而总共有 C(2*i, i )种分配方式,所以: dp[i] + (2i-2)张牌时先手必输的情况 + 1  == C(2*i,i)。

        AC代码:

using namespace std;
#include<vector>
#include<algorithm>
#include <numeric>
#include <string>
#define ll long long 
#include<set>
#include<bitset>
#include<iostream>
#include<map>
#include<queue>

const int N = 100;
int m, p, n;
ll ans[40];
int c[61][61];
int mod = 998244353;


void init() {
	/*
	*   1  1
	*   1  2  1
	*/
	for (int i = 1; i <= 60; i++) {
		c[i][0] = 1; c[i][i] = 1;
	}
	for (int i = 2; i <= 60; i++) {
		for (int j = 1; j < i; j++) {
			c[i][j] = c[i - 1][j - 1] + c[i - 1][j]; c[i][j] %= mod;
		}
	}
	ans[1] = 1;
	// ans[i] 表示有 2*i 张牌,先手必胜的分配数目。
	// 假设先手有2*i这张牌,则先手必胜
	// 假设先手没有2*i这张牌,则要使先手仍然获胜,则先手必须有2i-1这张牌
	for (int i = 2; i <= 30; i++) {
		ans[i] = (c[2 * i - 1][i - 1] + c[2 * (i - 1)][i - 1] - ans[i - 1] - 1 + 998244353) % 998244353;
	}
}
void sove() {
	cin >> n;
	cout << ans[n / 2] << " " << (c[n][n / 2] - ans[n / 2] - 1 + 998244353) % 998244353 << " " << 1 << endl;
}

int main() {
	int t = 1;
	init();
	cin >> t;
	while (t--) {
		sove();
	}
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值