CF2065 做题记录

赛时过了 ABDEF。G 改代码的时候忘删掉一个 continue,一直过不了。E 忘记判 k>max(n,m) 调了一年,还吃了一车罚时。C 赛时不会。

总结:烂完了。

A

直接模拟即可。

B

当序列中有两个相邻的相同的数时答案为 1,否则答案为 n

C

从左到右依次确定每个 ai,贪心地让 ai 在不小于 ai1 的情况下尽可能小。如果到某个地方无法使 aiai1 则无解。

D

先考虑一个简化问题:给定一个序列 {a},重排使得 i=1nSi 最大。

由于 i=1nSi=i=1n(ni+1)ai,所以越靠前的数被计算的次数越多,因此 {a} 升序排序时最优。

回到这个题,每个序列一开始被计算的部分不完整,之后一直累加整个序列的和。前面不完整的部分无论怎么重排都一样,后面的部分,由于每个序列长度相同,所以直接贪心地让按整个序列的和从小到大排序即可。

形式化地说,答案可以表示为:

i=1n((ni)mSi+j=1mk=1jai,k)

其中 Si 表示第 i 个序列的和。j=1mk=1jai,k 和序列的顺序无关,所以最大化前面那部分就行,因此按 Si 降序排列。

E

构造。设串 s 中有 x0y1,记 f(s)=|xy|,即题目中的“balance-value”。

先考虑无解情况:对于整个串,无论怎么排序,都有 f(s)=|nm|,所以当 k<|nm| 时无解,这是 k 过于小的极端情况。另一个极端是 k>max(n,m),此时同样无解。

下面不妨设 n>m。容易构造出策略:先放 k0,那么这个长为 k 的子串保证的整个串 f(s)=k。放完之后 nnk。之后放上多出来的 1,直到 n=m。最后放上 n01(或 10,根据之前最后一个字符而定)即可。容易发现这一定满足要求。

F

如果一条路径存在绝对众数 x,那么 x 出现的次数至少为 2。可以发现在这个路径中,要么有两个相邻的 x,要么有一个点同时和两个 x 相邻。(严谨证明参见官方题解,用了反证法。)而实际上,“两个相邻的 x”本身就已经构成了以 x 为绝对众数的路径,“有一个点同时和两个 x 相邻”同理,因此只需要判断这两种情况,这是简单的。时间复杂度 O(n+m)

G

赛时没有想清楚就开始写,浪费了很多时间!一定要把逻辑捋顺再写代码啊。

首先,由于 lcm(a,b) 相当于把 ab 的质因数分解上的每个指数取 max,所以如果 lcm(a,b) 是半质数,那么 a,b 一定都是质数或半质数,因此只需考虑这些数。

进一步,如果 lcm(a,b) 是半质数,那么 a,b 必然满足以下三种情况之一(设 p,qP):

  1. a=b=pqp,q 可以相等)
  2. a=p,b=pqa,b 反过来同理,p,q 可以相等)
  3. a=p,b=qpq

由于值域为 n,所以筛出 n 以内所有的素数,开一个桶记录每个数出现的次数,枚举所有的 ppq 类型的数,再用组合公式统计一下即可。

H

计数题!难点主要在于第一步的转化,后续的数据结构优化是顺理成章的。

按子序列计数显然是没有前途的,因为子序列的数量是 O(2n)。按照计数问题的套路,我们先改变计数对象

对于一个序列,它的权值是其极长的 01 连续段个数,所以我们不妨想想这些极长连续段是怎么出现的。除了第一个极长连续段,所有极长连续段的的开头第一个数必然和它前面一个数不同。也就是说,两个相邻的不同数贡献一个连续段。形式化的表述为:

f(s)=1+i=1n1[sisi+1]

因此可以枚举值不同的数构成的数对 (i,j)i<jsisj)。对于一对 (i,j),它对总答案的贡献就是使得 sisj 相邻的子序列个数。那么有多少个这样的子序列呢?这相当与钦定 sisj 必须选,si+1sj1 必须不选,其它位置可以选也可以不选。因此 (i,j) 对答案的贡献为 2i1+nj,总答案为:

ans=i=1n(2ni+j=i+1n[sisj]2i1+nj)

(加上 2ni 是考虑到 si 作为整个子序列的开头时的贡献,此时只有 i+1n 的位置可以任意选。)这样就导出了一个 O(qn2) 的做法。

考虑优化。把上式提出公因式变成

ans=i=1n(2ni+2i1j=i+1n[sisj]2 nj)

预处理一下 2nj 的后缀和,就可以做到 O(qn) 的时间复杂度。这里的瓶颈主要在于每次修改的时候都要重新算一遍后缀和。

到了这一步,已经可以 O(n) 计算出在没有修改时的答案。因此我们先计算出未修改时的答案,然后考虑每次修改对答案的影响,在把答案加上这个影响。

由于我们每次修改一个位置的值,因此我们写出一个位置 p 对答案的贡献 g(p)

g(p)=2np+2npi=1p1[sisj]2i1+2p1i=p+1n[sisj]2ni

第一项代表 p 作为子序列第一个值时的贡献,第二项计算形如 (i,p)i<p)的数对的贡献,第三项计算形如 (p,i)p<i)的数对的贡献。

(值得一提的是,ansi=1ng(i),因为 g(i) 统计了所有包含 i 的数对的贡献,所以对于每个数对 (i,j),它在算 g(i)g(j) 的时候都会被统计到,这样会算重。因此计算 ans 的时候一定要保证枚举的数对是有序的。但修改的时候我们考虑 i 的所有贡献,所以任何包含 i 的数对都要被计入其中。)

每次修改时,先减去 p 原来的贡献 g(p),再加上新的贡献 g(p)i=1p1[sisj]2i1i=p+1n[sisj]2ni 这两项需要单点修改和区间求值,用树状数组维护即可。(为了计算 [sisj] 这个因子,需要开两组树状数组分别维护 0 位置和 1 位置的值。说“两组”是因为每组都要开两个线段树分别维护 2i1 的和及 2ni 的和。)

综上所述,我们做到了 O(n+qlogn) 的时间复杂度。AC 记录

posted @   DengStar  阅读(44)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示