那些你不要的
idea from 127, data, solution from csy2005
算法一
每次删掉位置为奇数和偶数的数,那么所有位置的奇偶性不会变。
剩下来的数为奇数位置上的数,那么偶数位置上的数就没用了,就相当于每次删掉一个奇数位置上的数。
所以答案就是奇数位置上的数的中位数。
求解中位数可以直接排序,也可以使用 std::nth_element
。
时间复杂度为
期望得分
比特迷宫
idea, data, solution from JohnVictor
算法一
我会直接依次输出
算法二
我会暴力讨论相邻几位!讨论的多就能获得
算法三
考虑爆搜出所有相邻
算法四
直接贪心,先通过随机打乱使得
算法五
我们在构造的时候规定
一个关键的观察是,对于
现在,我们可以得到如下算法:首先通过至多一次操作将
通过贪心算法寻找
璀璨宝石
idea, data, solution from he_____he
算法一
首先我们一定是先拿足够多的宝石之后,再去拿所有发展卡。假设我们分别需要
暴力枚举每次拿哪张发展卡,对每种情况算出所需的每种宝石数量,复杂度
算法二
对于
算法三
对于
算法四
如果我们需要的轮次不是
通过
时间复杂度
算法五
我们抛弃算方案数的计算方法,想办法直接求出这个最大值。考虑这样一个过程:每一次取宝石相当于消了两个不同类型的宝石,我们首先随便消一些,直到出现一类宝石出现次数大于等于一半,我们把所有非这一类的宝石全部留着和这一类宝石相消。考虑用一个 dp 来还原这个过程。记
我们希望在转移过程中,每次消都是消了两个不同的宝石,这样我们得到的答案一定不会好于最优解。同时我们希望能够达到最优解。也就是存在一种转移,能够在前一半模拟出随便消(
更进一步的,每次转移都是拿取一张卡,我们可以依次考虑所有宝石种类,所以我们每次要做的就是考虑一些只有
我们尝试把转移挨个写下来:假设目前是
如果
,那么第 类宝石会多 个,会转移到 。如果
,那么这两类宝石之间可以相消,有以下两种情况:如果
,那么要么在消的过程中转移到了 状态,要么仍然处于 状态。后者为消(拿取)
次转移到 ,前者为消(拿取) 次转移到 状态中的 ,其中 ,表示我们用 和 消了 次,消之后 出现次数大于等于一半了,剩下的 和 都留着以后消 。如果
,那么要么在消的过程中转移到了 状态,要么仍然处于 状态。后者为消(拿取)
次转移到 ,前者为消(拿取) 次转移到 状态中的 ,其中 ,表示我们用 和 消了 次,消之后 出现次数大于等于一半了,剩下的 和 都留着以后消 。
第二种,假设目前是
- 如果
,那么我们正好要用前面留下的宝石消这 个宝石。- 如果
,直接消(拿取) 次转移到 状态的 即可。 - 如果
,同样直接消(拿取) 次转移到 状态的 即可(这里相当于剩下 个 没被消完,回到 状态仍然能保证我们不会消两个非 的宝石)。
- 如果
- 如果
,那么直接把这 个也留着消 ,转移到 状态的 。
转移复杂度
算法六
尝试优化转移。可以注意到,两种情况中,要么是在区间
把区间取最小值用数据结构优化可以做到每次转移
算法七
想办法把转移做到
对于
对于
这样单次转移所有状态就做到了
题外话
Splendor 真的很好玩!推荐大家都去尝试。
火星式选拔
idea, data, solution from ix35
算法一
用堆维护所有当前在队伍中的人,暴力模拟题目中的操作。
期望得分
算法二
考虑
设
我们要求的就是
期望得分
算法三
考虑区间中
于是我们只要考虑剩下的最后一个名额即可,这转化为了一个类似
用主席树维护区间前
期望得分
反重:求熵
idea from djq_cpp, solution, data from he_____he
算法一
暴力枚举所有情况。时间复杂度
算法二
对于
算法三
可以再把
算法四
整一点算法。考虑数位 dp,维护两两之间的两个限制目前处于什么状况,并需要记录每个数是否达到上界。状态最多
算法五
不从值域的角度考虑,转而尝试一个一个把变量消去。比如我们想要消去
时间复杂度
算法六
在上一个算法中,我们实际上做的是枚举
一个你可能的疑问是,我们不是还需要保证
这样复杂度就变为了
鸽子收费站
idea, solution from hehezhou, data from 127
考虑按时间顺序维护所有询问,对每个收费站依次处理。通过简单处理,题意即可转化为维护一个序列,支持:
- 单点修改
- 单点查询
- 将
中值在 的元素全部置为
以下均在描述转化后题意的解法,且认为
算法一
我会暴力!
直接
期望得分
算法二
若保证了
总复杂度
算法三
依然是考虑线段树。主要考虑第三种操作。如果我们能做到:仅当 当前节点区间与操作区间相交而不包含 或者 当前节点区间中有两种及以上的值需要修改 时,才继续递归,则所有修改访问的线段树节点数是
怎么判断 当前节点区间中有两种及以上的值需要修改 呢,这看起来没啥高论,考虑在每个线段树节点维护一棵平衡树,代表区间元素排序并去重后的结果。此时判断只需在平衡树上二分即可。但是不难发现这么做的问题:如果一个线段树节点代表的区间中只有一种值需要修改,但是这种值可能遍布整个区间,我们没法快速修改所有后代线段树节点的平衡树。
怎么做到“牵一发而动全身”呢,答案是把平衡树连起来。实际上对于上述问题,这个区间修改后,区间中值的相对顺序没有任何变化,也就是平衡树的结构并不需要改变。考虑只在线段树根节点的平衡树上维护具体的元素值,对于其他线段树节点的平衡树,每个平衡树点连向线段树上父亲所在平衡树中,值相同的平衡树点。这样一来,如果一个线段树节点代表的区间中只有一种值需要修改,只需要通过某种方式修改当前节点平衡树中对应点代表的值,线段树后代节点无需继续递归修改。
在这个结构上修改,所有操作需要修改的线段树总节点数就是
对于查询操作,直接找到线段树叶子,然后从对应平衡树节点不断在线段树上向上跳到根即可得到真实值,复杂度
对于单点修改操作,直接通过递归操作不断找到平衡树中应该插入的位置完成,复杂度
对于区间修改操作,通过递归操作不断求出当前节点
因此总复杂度