Codeforces Round 792
F
题目
https://codeforces.com/contest/1684/problem/F
长n数组a
m个区间[l,r]
自己任选一个范围(与上面的区间无关),修改区间中所有值成任意值, 让上面区间每个区间都没有重复的数
问 你任选的区间最短长度
范围
n 2e5
m 2e5
ai 1e9
2s
256MB
题解
我的思路
ai和n不成比例,与具体值无关, 无脑离散化一下,把ai范围降低到n
对于一个区间[l,r], 如果覆盖了一侧,如[l0,r],那么其实很好求l0的最大值(因为要区间尽量小
只需要通过v2idx[v] = last index
, 跳一跳就行了
那么其实可以得到 这些l0 中最小的l0, 记为 L, 同样可以得到最大的R
那么 答案一定是包含了[L,R]
的
那么问题变成了, 如果就是给你一个区间,但是是部分覆盖如何做到最短, [l,r] 你要找 [l...[L..R]...r]
其中 [l..L-1][R+1..r]
不存在重复的数,还要[L,R]
最短
方法
如果答案是[L,R]
也就是 任何给的线段[l,r]中,不存在相同值都不属于[L,R]
,
先让L = 1
, 那么找r
跟上面说的一样, 找到max(min(ri))
然后,如果L左移1,R会如何变化
如果[L+1,R]
满足则就是R
否则R
只能增大, 甚至 L+1
就无法合法了
注意到 如果有同样的l
,那么只用考虑r
更大的即可
[L..R] => [L+1..?]
首先 如果 [lastpos[v[L]]...L]
被包含在某个区间中, 那么必定不可行, 之后更大的L也不可行了break掉
如果 大于R的 value = v[L]的 位置在p
且[L...p]
在某个区间中, 那么必定[L+1..R]
不合法
[L+1...p]
则是新的合法的
上面两个都需要的是查询 左端点在[0...pos]
中的给定线段, 右侧端点最大值
这个注意到是一次赋值,多次查询没有更改的,直接前缀最大值
代码
https://codeforces.com/contest/1684/submission/158651275
1 |
|
G
题目
https://codeforces.com/contest/1684/problem/G
t 是一个数组
考虑Euclid求gcd
1 | function Euclid(a, b): |
p 是一个包含不超过m的正数对的数组
t 初始为空
然后 对p的所有 数对 运行上述算法
t然后被打乱了给你
你需要找一个 数组, len <= 2e4, 能产生 t, 或者判断它不可能存在
范围
len(t) 1e3
m 1e9
1 <= ti <= m
1s
256mb
题解
我的思路
其实就是 辗转相除(a,b), a>b
中间的所有非零余数
b > v, a >= b + v > 2v
所以如果有值不满足m > 2v
则直接不可能输出-1
否则直接无脑2v+1,v+1
?, 但注意到2v+1,v+1,v,1
还会产生1, 也就是不行的
另外3v,2v,v
不会有额外产生,如果有多余的3v <= m
可以这样处理掉
所以只用考虑3v > m > 2v
的v值m/2 > v > m/3
(非整除)
a = 2v+i,b = v+i,v,i,...
(i <= m-2v < v)
但怎么选i, 以及处理之后的余数,并没有任何想法
v的选择可以从大到小, 这样也可能消耗掉 一部分 m/2 > v > m/3
题解
一样 先把v的范围限定在了3v > m > 2v
, 范围以外的和我想的一样的处理
m >= a=2v+i,b=v+i,v,i,...
也就是考虑到 2v + gcd(v,i) <= 2v+i <= m
也就是对于每个 v > m/3
, 一定存在一个是它因数的x
,且2v + x <= 2m
于是建立二分图
左边 > m/3, 右边 <= m/3
做二分图匹配即可
我的问题,在i 和 m/3大小判断错了, 其实 2v+i = a <= m
和v > m/3
就可以得到i < m/3
的
这样的话,v必然是靠小于等于m/3的消耗掉的,不如直接贪约数
有一说一,写起来其实会比F简单?
代码
https://codeforces.com/contest/1684/submission/158654516
1 |
|
H
题目
https://codeforces.com/contest/1684/problem/H
给0/1串s, 切分成任意多个不相交子串, 然后让这些子串表示的二进制值的和是2的幂次
范围
|s| 1e6
2s
256mb
题解
我的思路
如果1的个数是2的幂次, 那么直接全部拆碎就完了
不妨设一共有$w$个1,且 $2^k < w < 2^{k+1}$
除了最后一位1, 任何一个1 都可变成2的贡献,不论是通过 11还是10, 它对w的贡献就是+1
但是如果连续的两个1,至多有一个可以贡献2,
同样除了最后两位1, 任何一个1 都可变成4的贡献,通过1XX, 对w贡献是+3
但是如果连续的三个中出现的1,至多有一个可以贡献4,
所以 (w-2)/3 个1 可以变成贡献4, 于是可以多贡献 (w-2)
但值得注意的是, 之所以 (w-2)/3 一个是因为尾部, 一个是因为 连续的3个中出现1, 才会不能让所有的1贡献4, 下限是(w-2)/3
这样的话,也就是说 有部分的贡献的是2, 总可以补全到$>= 2^{k+1}$
1 | 100 = 4 (+3) |
所以对于所有1开头的3位, 有的贡献可以+1,+3, 有的贡献可以+1,+4
2^{k+1}-1 >= w >= 2^k+1
所以 通过+3,+4 让w和 2^{k+1}的距离 在某个3元组能达到[1,3]
之间, 剩下的[1,3]
就靠+1
补满
且, 注意到如果是靠不少+3达到的,那么剩余的长3的组一定还不少, 不会耗尽所有
所以w足够大时,必定可行
需要考虑w小的时候, 但多么小呢?
w = 1,2,4,8直接可行
w = 3 时, dst = 4. +1 必定可行
w = 5 时, dst = 8, 需要+3, (111)(110)
就是个不能用上面切割达到的
w = 6,7 时, dst = 8, 需要+2/+1, 必定两/一次+1可以达到
w = 9 时, dst = 16, 需要+7, (111)(111)(111)
,也是不能用上面切割达到
w = …
这块细节就不知道怎么搞, 也不知道大于多少以后w一定可以
方法
1,2,4,等2的幂次, 直接切碎
k = 3 可以用上面我说的方法
k = 5
如果1连续, 1111+1 = 10000
否则1之间存在0, 存在一个0,则101存在,多个0,则100存在. 101+1+1+1=1000, 100+1+1+1+1 = 1000
k > 5
solve(l,r,k,n) 函数表示把有k个1的[l..r]段切来和为n
这里目标n也是放在 2的log(2,k)向上取整幂次,
足够大的n, 考虑是按照k 来切开, 让它分别为 k/2向下取整和 k/2向上取整, 并且 让它们的和都是 n/2
solve(l,r,k,n) = solve(l,pos,k/2,n/2) and solve(pos+1,r,k-k/2,n/2)
然后界限来就是说 k = 6..11 时 如何搞
这里其实可以自己随便乱搞了,毕竟范围有限,目标明确
官方英文题解里有具体方法
这里方法上有一个要注意的是, 当 1的个数是 (2的幂次)+1
时, 它期望切割出来的2的(幂次-1)
那一部分还是需要到
比如 17 = 16+1
个1, 期望的结果是 2**5 = 32
17 = 8+9
, 9
的期望结果是16
没问题, 但是8
也需要16
而不是得到8
但注意到这个问题集中在2的幂次上
所以再向下考虑4个1要得到8
考虑最左1开头的数:
111
: 111+1=1000
110
: 110+1+1 = 1000
101
: 后面一个1贡献2,1个1贡献1, 101+10+1 = 1000
100
: 后面一个1贡献2,两个1贡献1, 100+10+1+1 = 1000
都可以得到8
代码
鸽, 构造+枚举小值 是我太菜了
总结
F:
一个是 包含两个相同值,转化成包含两个相邻相同值,因为同样的值出现多次, 只用考虑相邻 v…v…v, 只用考虑[v…v]…v 或v…[v…v]
看起来没离散2e5个<1e9的map效率还行啊, 仅仅是查询的话
双指针 + 滑窗还是写不熟啊
G:
这里主要在i的范围判断错了,如果 i > m/3 那么 2v+i >= 2m/3 + m/3 = m
, 我数学太菜了
H:
从小特例开始考虑算是有一定思路是对的, 但是要敢于分情况讨论
但是这个分治的确没想到,就算想到一半, 可能没想到让k/2向下和向上取整,都去等于 n/2
或者整体来说, 没想到 和可以拆成 和的一半 对应 1个数的一半
特别是这里敢于 2的幂次+1这种数也这样拆