CF2030E MEXimize the Score 题解
题面
假设我们将数组 \(b\) 中的元素分割成任意多个 \(k\) 的非空多集 \(S_1, S_2, \ldots, S_k\) ,其中 \(k\) 是一个任意的正整数。定义 \(b\) 的分值为任意整数 \(k\) 的 \(\operatorname{MEX}(S_1)\) \(^{\text{∗}}\) $ + \operatorname{MEX}(S_2) + \ldots + \operatorname{MEX}(S _ k)$ 在 \(b\) 的所有可能分区中的最大值。
给 Envy 一个大小为 \(n\) 的数组 \(a\) 。由于他知道计算 \(a\) 的得分对你来说太容易了,所以他要求你计算 \(a\).\(^{\text{†}}\) 的所有 \(2^n - 1\)$$ 非空子序列的得分之和。由于这个答案可能很大,请输出它对 \(998,244,353\) 取模的结果。
整数集合 \(c_1, c_2, \ldots, c_k\) 中的 \(^{\text{∗}}\) \(\operatorname{MEX}\) 定义为在集合 \(c\) 中不出现的最小非负整数 \(x\) 。例如, \(\operatorname{MEX}([0,1,2,2]) = 3\) 和 \(\operatorname{MEX}([1,2,2]) = 0\) 。
\(^{\text{†}}\) 如果 \(x\) 可以通过删除几个(可能是零个或全部)元素从 \(y\) 得到,那么序列 \(x\) 就是序列 \(y\) 的子序列。
题解
记 \(cnt_i\) 表示数字 \(i\) 在可重集合中出现的次数,对于单个集合,我们很容易知道一个最完美的划分可以达到的分数是 \(cnt_0 + \min(cnt_0+cnt_1) + \ldots + \min(cnt_0+cnt_1+\ldots+cnt_{n-1})\),贪心的考虑把相同的数字分到不同的集合,必定可以构成 \(0\) 到 \(t\) 的一个排列,此时的 \(\operatorname{MEX}\) 和可以达到最大,接下来我们考虑如何求出所有子集的价值和。
不妨设有这样一个集合,这个集合的价值可以通过构造一个 \(0, 1, ..., t\) 排列得到,排列存在当且仅当:
\]
因此我们考虑分成的子集排列分别能得到的价值,可以发现,这个排列中的每一个元素恰好贡献 \(1\),求每个排列中元素的价值总和转换成求每个元素对所有排列的总贡献。
假定最开始所有的集合并为空集,我们逐个插入元素,使得所有集合的并恰好不重复的是 \(S\) 的一个子集。
记 \(f(t) = \sum\limits_{i = k}^{cnt_t}\binom{cnt_t}{i}\),容易发现 \(f(t)\) 相当于把 \(t\) 元素插入 \(i\) 个不同的集合中,相当于把这些元素先插入 \(k\) 个 \(0 \sim t - 1\) 的排列中,这部分元素有 \(1\) 的贡献,剩余的 \(i - k\) 个元素也插入集合中,但是此部分元素没有直接贡献,仅仅可以让集合并变成一个新的子集 ,剩余的 \(r\) 个元素也可以组成 \(2^r\) 个集合,这些集合插入进去也不会影响现有的答案的贡献,因为我们仅仅计算的是元素 \(t\) 产生的贡献,他们可以任意插入已有的排列中,并且不改变 \(t\) 存在的价值。
我们不妨枚举 \(k\),对于每个 \(k\),我们考虑尽可能长的构建 \(k\) 个 \(0 \sim t\) 排列,容易知道最大的 \(t\) 满足 \(\min(cnt_0, cnt_1, \ldots, cnt_{t}) \ge k\),同样,对于每个 \(t\) 我们也需要去计算他的答案。
对 \(0\) 元素来说,拿出 \(k\) 个元素作为合法集合,共有 \(\binom{cnt_0}{k}\) 种不同集合并形式,再考虑将多余的 \(0\) 任意插入进去,这部分的贡献是 \(f(0)\),对于除了 \(0\) 以外的剩余 \(r\) 个元素,可以任意放入集合并且不影响答案,根据乘法原理,贡献是所有操作的种类数的积,此部分的 \(0\) 的答案与并出来的子集数量一致,直接加到答案上即可。
到 \(t\) 元素时,同样,对于前 \(t - 1\) 的元素已经考虑插入完成,有 \(\prod\limits_{i = 0}^{t - 1}f(i)\) 种子集,此时插入方式有 \(f(t)\) 种,对于其后的元素同样考虑是否加入,也有 \(2^r\) 种方式,至此,我们的答案就可以通过上述方案递推求出。
发现 \(\sum\limits_{i = 0}^{n - 1}cnt_{i} = n\),因此时间复杂度为 \(O(n)\),不会超时。
参考代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 2e5 + 10, mod = 998244353;
int n, a[N], suf[N], pow2[N], frac[N], inv[N];
ll ksm(ll a, ll k)
{
ll res = 1;
while (k)
{
if (k & 1) res = res * a % mod;
k >>= 1;
a = a * a % mod;
}
return res;
}
void init()
{
pow2[0] = frac[0] = 1;
for (ll i = 1; i < N; i ++ ) pow2[i] = 2ll * pow2[i - 1] % mod, frac[i] = frac[i - 1] * i % mod;
inv[N - 1] = ksm(frac[N - 1], mod - 2);
for (ll i = N - 1; i; i -- ) inv[i - 1] = inv[i] * i % mod;
}
int binom(int a, int b)
{
return 1ll * inv[b] * inv[a - b] % mod * frac[a] % mod;
}
void solve()
{
cin >> n;
vector<int> cnt(n);
for (int i = 1; i <= n; i ++ ) cin >> a[i], cnt[a[i]] ++ ;
suf[n - 1] = 1;
for (int i = n - 1; i; i -- ) suf[i - 1] = 1ll * suf[i] * pow2[cnt[i]] % mod;
ll ans = 0, p = 0;
vector<int> f(n), g(n);
g = cnt;
for (int k = n; k; k -- )
{
while (p < n && cnt[p] >= k) p ++ ;
ll res = 1;
for (int i = 0; i < p; i ++ )
{
while (g[i] >= k) (f[i] += binom(cnt[i], g[i])) %= mod, g[i] -- ;
res = res * f[i] % mod;
(ans += res * suf[i] % mod) %= mod;
}
}
cout << ans << endl;
}
int main()
{
init();
int T;
cin >> T;
while (T -- ) solve();
return 0;
}
CF2030E MEXimize the Score 题解的更多相关文章
- C++版 - UVa1585 Score - 题解
C++版 - UVa1585 Score - 题解 <算法竞赛入门经典(第二版)> 习题3-1 得分(ACM/ICPC Seoul 2005,UVa1585) 问题描述: 给出一个由O和X ...
- 2016 华南师大ACM校赛 SCNUCPC 非官方题解
我要举报本次校赛出题人的消极出题!!! 官方题解请戳:http://3.scnuacm2015.sinaapp.com/?p=89(其实就是一堆代码没有题解) A. 树链剖分数据结构板题 题目大意:我 ...
- ZOJ 3819 Average Score(平均分)
Description 题目描述 Bob is a freshman in Marjar University. He is clever and diligent. However, he is n ...
- 洛谷P2722 总分 Score Inflation
P2722 总分 Score Inflation 184通过 295提交 题目提供者该用户不存在 标签USACO 难度普及- 提交 讨论 题解 最新讨论 关于算法 题目背景 学生在我们USACO的 ...
- UVA 12906 Maximum Score 排列组合
Maximum Score Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://acm.hust.edu.cn/vjudge/contest/vie ...
- hdu 5268 ZYB loves Score 水题
ZYB loves Score Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://acm.hdu.edu.cn/showproblem.php?p ...
- 大家AK杯 灰天飞雁NOIP模拟赛题解/数据/标程
数据 http://files.cnblogs.com/htfy/data.zip 简要题解 桌球碰撞 纯模拟,注意一开始就在袋口和v=0的情况.v和坐标可以是小数.为保险起见最好用extended/ ...
- 【2013南京区域赛】部分题解 hdu4802—4812
上周末打了一场训练赛,题目是13年南京区域赛的 这场题目有好几个本来应该是我擅长的,但是可能是太久没做比赛了各种小错误代码写的也丑各种warusn trush搞得人很不爽 全场题之一的1002也没有想 ...
- HDU1789(Doing Homework again)题解
HDU1789(Doing Homework again)题解 以防万一,题目原文和链接均附在文末.那么先是题目分析: [一句话题意] 给定任务分数和其截止日期,每日可完成一任务,输出当罚分尽可能小时 ...
- Score(规律)
Score Time Limit : 5000/1000ms (Java/Other) Memory Limit : 32768/32768K (Java/Other) Total Submiss ...
随机推荐
- .net framework创建Nuget包简要教程
前言 nuget包生成在.net framework和.net core/.net standard下的是不同的. .net framework中稍微复杂些,下面记录了我自己在.net framewo ...
- animate动画库的使用
在vue中便捷使用animate动画库效果. 安装animate动画库 npm install animate.css --save 在vue跟目录中 main.js 导入animate动画库 imp ...
- Python新手爬虫一:爬取影片名称评分等
豆瓣网站:https://movie.douban.com/chart 先上最后的代码: from bs4 import BeautifulSoup from lxml import html imp ...
- WKCTF RE
WKCTF so_easy 安卓逆向,关键的check逻辑都在native层里面 主要是很多层的异或操作 除了Z3和爆破想不到其他方法了 from z3 import * src = [ 0xAE, ...
- vue自定义组件的点击事件失效
在vue开发过程中为了减少重复代码,很多时候都需要将重复的部分写成一个组件,方便调用.但是使用组件时很可能又会给该组件添加点击事件.如果直接这样写,事件则会失效: 正确写法应该是这样:
- 【YashanDB知识库】生成迁移报告失败,"报错未知类型错误异常:"
[标题]YMP迁移 [问题分类]迁移报告 [关键字]迁移报告.未知类型错误异常 [问题描述]下载迁移报告时报错"未知类型错误异常:",一长串英文 日志报错: [问题原因分析]jav ...
- webpack笔记-webpack基础用法(二)
webpack 本质上是一个打包工具,它会根据代码的内容解析模块依赖,帮助我们把多个模块的代码打包. 一切文件:JavaScript.CSS.SCSS.图片.模板,在 Webpack 眼中都是一个个模 ...
- Angular 18+ 高级教程 – Component 组件 の ng-template
前言 上一篇 Dynamic Component 我们有提到,作为 MVVM 框架的 Angular 需要有方法替代掉 2 个 DOM Manipulation: document.createEle ...
- 理解IO多路复用
I/O 多路复用是什么? I/O 多路复用是用户程序通过复用一个线程来服务多个 I/O 事件的机制,我们也可以将他说成是一个线程服务多个文件描述符 fd,而 I/O 多路复用是在操作系统层面实现提供的 ...
- .NET常见的几种项目架构模式,你知道几种?(附带使用情况投票)
前言 项目架构模式在软件开发中扮演着至关重要的角色,它们为开发者提供了一套组织和管理代码的指导原则,以提高软件的可维护性.可扩展性.可重用性和可测试性. 假如你有其他的项目架构模式推荐,欢迎在文末留言 ...