AT2346 [ARC070B] No Need
这里介绍几种做法。
解法一
首先可以转化一下题意,\(\forall i\) 如果 \(i\) 不是可有可无的当且仅当不用 \(i\) 能拼出 \([K - a_i, K)\) 中的数。
基于观察可以发现,对于 \(\forall i\) 如果 \(i\) 不是可有可无的,那么 \(\forall j, a_j \ge a_i\) 都不是可有可无的,证明如下:
取出使得对于 \(i\) 能拼出 \([K - a_i, K)\) 中一个数的集合 \(S\),分以下两种情况讨论:
若 \(j \in S\),考虑用 \(a_i\) 替换 \(a_j\) 使得对于 \(j\) 合法。
则可知 \(K - a_i \le |S| \le K \Rightarrow K \le |S| + a_i \le K - a_i\)
于是有 \(K - a_j \le |S| + a_i - a_j \le K + a_i - a_j \le K\) 因此替换是可行的。
若 \(j \notin S\) 直接使用 \(S\) 即可满足 \(j\) 的要求。
因此我们先按照 \(a_i\) 从小到大排序,可替换的必然是一段前缀,直接二分加背包判断即可,复杂度 \(O(nk \log n)\)。
解法二
一个直接的想法在于求出不使用 \(i\) 能拼成的数字有哪些。
暴力的做法就是 \(\forall i\) 枚举 \(j \ne i\) 进行暴力 \(dp\)。
但是你会发现有对于一些 \(i\) 有很多 \(j\) 都是能枚举的,换而言之每一对点对 \((i, j)(i < j)\) 都会在 \(i, j\) 上分别用对方 \(dp\) 一次。
对于这种点对对答案的贡献问题,经常可以考虑使用 \(\rm CDQ\) 分治解决。
那么我们在分治 \([l, r]\) 这个区间时可以发现,\([l, mid]\) 内的所有数会对 \([mid + 1, r]\) 内所有数的 \(dp\) 数组造成贡献。
因此我们直接考虑枚举左区间的每个数 \(i\) 让其在右区间恰好 \(dp\) 一次,对于右区间同理。
那么分治下去的时候就要同时将整个区间的 \(dp\) 数组传递下去,不难发现这样的复杂度实际上只枚举了 \(n \log n\) 个点,因此复杂度是 \(O(nk \log n)\) 的。
解法三
注意到我们要求的实质上是去除掉 \(i\) 以后的 \(dp\) 数组,不难让我们想起了 消失之物 这题的退背包做法。
但是本题的 \(dp\) 是判定性的,不存在可加性,怎么办呢?
不难发现只需要改写 \(dp\) 状态让其满足可加性即可,即我们将存储的值由是否可行变为方案数。
那么一个数不能被拼出来当且仅当方案数为 \(0\)。
于是先 \(dp\) 出总方案数,然后从左至右做退背包即可。
由于方案数过大,需要取模,复杂度 \(O(nk)\)。
解法四
考虑另一个暴力合并 \(dp\) 数组的做法,先记录 \(pre, suf\) 两个前缀/后缀 \(dp\) 数组。
\(\forall i\),在 \(i\) 处暴力合并 \(pre_{i - 1}, suf_{i + 1}\),复杂度 \(O(nk ^ 2)\)。
但实际上我们并不关心具体的 \(dp\) 数组,我们只关心 \([K - a_i, K)\) 之间有没有一个数能被拼出来。
为了尽量满足存在这样一个数,我们这样来看待这个问题:在满足和小于 \(K\) 的情况下最大化总和。
因此在合并的时候我们从小到大枚举 \(pre_{i - 1}\) 中一个可行的数 \(j\),找到 \(suf_{i + 1}\) 中满足 \(j + k < K\) 的最大的 \(k\)。
不难发现在 \(j\) 从小到大枚举的过程中,\(k\) 单调不升,因此这样寻找的复杂度就变为了 \(O(nk)\)。
对于解法一,其精髓在于通过观察获得的题目优秀性质。
对于解法二,其精髓在于将问题转化成点对之间的贡献问题,可以使用 \(\rm CDQ\) 分治优化。
对于解法三,其精髓在于将判定性问题转化成计数问题,满足可加性后就可以退背包。
对于解法四,其精髓在于去除了无用的一些状态,只寻找最用状态以降低复杂度。
四种做法各有优劣,但除做法二外其余的做法具有较大的局限性。
但可以发现的是,做法二可以解决很大一部分去除掉某个点后整体能够到达的状态,是一个通用的 \(\rm trick\)。
AT2346 [ARC070B] No Need的更多相关文章
- AT2346 No Need
atcoder上的题目 链接 一道思维题目 可以发现如果X是可有可无的,那么所有小于X的数也一定是可有可无的, 所有我们只要找出最大的那个可有可无的数字就好了 进一步分析,发现 若A1, A2, . ...
随机推荐
- Causal Intervention for Weakly-Supervised Semantic Segmentation
目录 概 主要内容 普通的弱监督语义分割 因果模型 训练流程 代码 Zhang D., Zhang H., Tang J., Hua X. and Sun Q. Causal Intervention ...
- [linux]ubuntu18.04 屏幕分辨率不适应问题
今天换了新显示器,发现更大的屏幕不适应原有的屏幕分辨率,看起来特别变扭. 在设置处查看最高分辨率仅为1024*748,没有与屏幕相适应的1920*1080(16:9). 解决方式: 1. 终端输入命令 ...
- ORA-09925:Unable to create audit trail file 数据库启动失败
问题描述:生产库停机加内存和CPU,重启完服务器,启动数据库报错. ORA-09925: Unable to create audit trail file Linux-x86_64 Error 2: ...
- 图像数据到网格数据-2——改进的SMC算法的实现
概要 本篇接上一篇继续介绍网格生成算法,同时不少内容继承自上篇.上篇介绍了经典的三维图像网格生成算法MarchingCubes,并且基于其思想和三角形表实现了对样例数据的网格构建.本篇继续探讨网格生成 ...
- Rainbond 对接 Istio 原理讲解和代码实现分析
一.背景 现有的 ServiceMesh 框架有很多,如 Istio.linkerd等.对于用户而言,在测试环境下,需要达到的效果是快.开箱即用.但在生产环境下,可能又有熔断.延时注入等需求.那么单一 ...
- Flink sql 之 两阶段聚合与 TwoStageOptimizedAggregateRule(源码分析)
本文源码基于flink1.14 上一篇文章分析了<flink的minibatch微批处理>的源码 乘热打铁分析一下两阶段聚合的源码,因为使用两阶段要先开启minibatch,至于为什么后面 ...
- monkey怎么做APP自动化?
前言: monkey是andriod平台自动化测试的一种手段,通过monkey程序模拟触摸屏幕.滑动,滚屏,按键来对设备进行压力测试,检测程序多久会出现异常第一种:设置好命令,做随机自动化 什么时候可 ...
- Python_类型转换
列表与字符串互相转换 join方法将list转换为string _list = ["a", "b", "c"] # 以".&quo ...
- django创建促销系统
创建应用(coupons) 把应用添加到settings.py文件中 创建数据模型 创建优惠码表单forms.py 添加到admin后台,方便控制 运行命令python manage.py makem ...
- HTML5元素
1.1结构元素 HTML5定义了一组新的语义化标签,目前主流浏览器均已支持,语义化标签使用标记元素的内容,虽然可以使用原有标签替换,但是它可以简化HTML页面设计,并且也为搜索引擎在抓取和索引网页的时 ...