题目描述:
题目大意: 有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张,也就是这时候的先手必胜,转换成了对方先手但只有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;
}