【组合数】2021ICPC济南补题-C Optimal Strategy
Description
Ena and Mizuki are playing a game.
There are n items in front of them, numbered from to . The value of the -th item is . Ena and Mizuki take turns to move, while Ena moves first. In a move, the player chooses an item that has not been taken and takes it away. The game ends when all items are taken away. The goal of either player is to maximize the sum of values of items they have taken away.
Given that both players move optimally, how many possible game processes are there? Since the number may be too large, you should output it modulo .
Two processes are considered different if there exists some integer such that the indices of items taken away in the -th move are different.
Input
The first line contains an integer .
The second line contains n integers .
Output
Output the answer.
Sample Input 1
3
1 2 2
Sample Output 1
4
Sample Input 2
6
1 3 2 2 3 1
Sample Output 2
120
Sample Input 3
12
1 1 4 5 1 4 1 9 1 9 8 10
Sample Output 3
28800
Explanations
In the first example, there are four possible processes:
- .
- .
- .
- .
Here means that in the first move Ena takes away the -th item, in the second move Mizuki takes away the -th item, and in the final move Ena takes away the -th item.
Note that is not a possible process, since the second move is not optimal for Mizuki.
题意
给定n个物品和其价值(数值可以重复),Ena和Mizuki轮流取物品,每个人的得分是其所取物品的价值总和,Ena先手,每个人取的都是当前的最优,问到过程结束(结果不变)中间有多少种取法的过程。
思路
(直通车:官方的一句话题解,考虑最大值如果是偶数个,那么会每次被两个两个的取;如果是奇数个,那么会被先手立刻取走一个,变成偶数的情况。)
(赛中看到1e6想是写出线性,其实不是线性,很痛苦,思路特别杂乱,本次记录思考过程也是反思)
首先知道 到的数值,就相当于已经知道了结果,并且结果一定是先手赢或者是平局(如果后手有赢的策略,先手一定会先拿),知道这个并没有什么用处。
由于下标不同,数值相同的数取来也能算一种不同方案,这里可以直接按照同数值的个数计数,用表示数值出现的次数。设为当前所剩数中的最大值,为当前所剩数中的最小值。
怎么想到和奇偶性质有关呢?
先不管样例1里面先手知道自己必胜所以先取相对小的数也不影响结果的操作,就用贪心的思路想一想。对过程分析一步步分析,如果是奇数个,若要符合最优策略,先手必定拿走第一个和剩下的一半,若是偶数个,两人肯定对半分,这对所有的剩下的数都适用,所以奇数情况的下一步就是偶数情况,这里可以想到和数值个数有关系了,所以最优取法的过程中,每个数值一定是两个两个配对着取。
对取法过程进行分析,先不贪心,因为从大到小考虑很难分析单个过程(在这里被卡死了),不如从小的值到大的值考虑。
先手取,后手取剩下的数中的的话。
如果上一步对家没有拿当前的,说明当前的在自己这里所有的数中一定是最大,或者是和最大值相等的,所以可以放在当前的所取的数的策略,前面的任意一步取得。并且,由于从小到大遍历,现在自己取了,前面的数是都不符合贪心策略的,因为它们都比小,只有后面的数要符合贪心,所以前面的数在前面的过程中可以按照任意顺序取。
取法过程分析完了,求一个公式。
在当前最大值是时,取的过程会有种,因为下标不同取来也算一种不同的取法
由于要符合最优策略,当前的一定是贪来保证个数到 的
但是自己取的数不一定只有一种,并且不用保证最先取到,只要保证的个数,前面小于的值可以随便拿
所以可以得知,数值由小到大遍历的过程中自身的取法个数:
设为当前的值,前面小于的数都取到了,保证的个数是取到了个,过程随便拿,所以这些策略取法的总和是种
所以最后答案是:
优化:组合数,组合数的逆元需要预处理,的求和可以用前缀和优化,细节问题就是取模之类。
复杂度
AC代码
#include <bits/stdc++.h>
using namespace std;
#define inf 0x3f3f3f3f
#define llinf 0x3f3f3f3f3f3f3f3f
#define int long long
#define ull unsigned long long
#define PII pair<int,int>
#define endl '\n'
const int N = 1e6 + 10;
const int mod = 998244353;
const double pi = acos(-1.0);
typedef long long ll;
using namespace std;
int t, n;
int fact[N];
int invfact[N];
int presum[N];
int a[N];
int cnt[N];
int quickpow(int a, int b) {//快速幂
int res = 1;
while (b > 0) {
if (b & 1) res = res * a % mod;
b >>= 1;
a = a * a % mod;
}
return res;
}
int getinv(int a) { return quickpow(a, mod - 2); }//费马小定理求逆元
void init() {//预处理阶乘和阶乘的逆元
fact[0] = 1;
for (int i = 1; i < N; i++) {
fact[i] = fact[i - 1] * i % mod;
}
invfact[0] = 1;
invfact[N - 1] = quickpow(fact[N - 1], mod - 2);
for (int i = N - 2; i > 0; --i) {
invfact[i] = invfact[i + 1] * (i + 1) % mod;
}
return;
}
int C(int n, int m) {//组合数
return fact[n] * invfact[m] % mod * invfact[n - m] % mod;
}
void solve() {
for (int i = 0; i <= n; i++) {//初始化
a[i] = 0;
cnt[i] = 0;
}
for (int i = 1; i <= n; i++) {//输入
cin >> a[i];
cnt[a[i]] ++;
}
presum[1] = cnt[1];
for (int i = 2; i <= n; i++) {//cnt[i]的前缀和
presum[i] = presum[i - 1] + cnt[i];
}
int sum = 1;
for (int i = 1; i <= n; i++) {//按公式求和
sum = sum * fact[cnt[i]] % mod * C(presum[i - 1] - presum[0] + cnt[i] / 2, cnt[i] / 2) % mod;
}
cout << (sum) % mod << endl;//输出
return;
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
init();
while (cin >> n) {
solve();
}
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南