CF散做

比较牛的/想写题解的可能会单独发一篇文章。

ds

CF380C. Sereja and Brackets

第一眼肯定是用线段树维护矩阵来搞对吧,但是这个状态有点厉害,很牛。

一个位置维护三个信息 \(x,y,z\)。他们分别表示最长匹配子序列的长度、未进入答案的左括号个数、未进入答案的右括号个数。合并 \((x_1,y_1,z_1)(x_2,y_2,z_2)\) 的时候就是令 \(t=\min(y_1,z_2)\),答案是 \((x_1+x_2+2t,y_1+y_2-t,z_1+z_2-t)\)

有点神奇,想不到。

CF1379C. Choosing flowers

注意到至多有一个物品会被选超过一次,剩下的就很简单了。

感觉好像和 ds 没什么关系。

CF52C. Circular RMQ

题很简单,没什么好说的。学到了一种读入一行个数不确定的数的方法。

点击查看代码
string _;getline(cin,_);stringstream __(_);
vector<int>v;int x;while(__>>x)v.push_back(x);

CF558E. A Simple Task

典中典。指路:P2824 [HEOI2016/TJOI2016]排序ABC237G - Range Sort Query

简单写下做法:因为值域很小,你可以枚举每种字母,把小于它的看成 0,反之为 1,排序操作就成了区间赋值。如果 \(p\) 在枚举到 \(c,c+1\) 时结果不一样就说明 \(s_p=c\)

CF446C. DZY Loves Fibonacci Numbers

可以看 这篇博客

CF1822G2. Magic Triples (Hard Version)

根号分治的思想。

考虑枚举中间的数 \(a_i\),公比可以枚举 \(a_i\) 的因数,这样可以过 easy version。

然后你发现对于 \(a_i\ge 10^6\),你只需要枚举至多 \(10^3\) 个数,其余情况可以沿用 G1 的做法,复杂度平衡到了 \(\mathcal{O}(\sqrt[3]{A}\times n\log n)\)。或许哈希表可以把 log 干掉。

不知道为啥能过,但是根号分治想法不错。

CF455E. Function

可以看 这篇博客

CF19D. Points

可以看 这篇博客

CF794F. Leha and security system

可以看 这篇博客

CF958C3. Encryption (hard)

可以看 这篇博客

CF452F. Permutation

可以看 这篇博客

CF914D. Bash and a Tough Math Puzzle

哎,脑瘫。

这个询问等价于问区间不是 \(x\) 的倍数的数是否不超过一个,考虑线段树。每次询问,我们直接暴力递归找不是 \(x\) 的倍数的数,如果已经超过一个就返回。因为我们至多只会找两个,所以复杂度其实是 \(\mathcal{O}(n\log n\log A)\) 的。

CF341D. Iahub and Xors

其实学会了二维 BIT 就很简单。

CF1109E. Sasha and a Very Easy Test

\(\text{mod}\) 分解质因数后开线段树维护即可。不明白为什么评 *2700,可能是稍微难写了一点?

CF813E. Army Creation

被 *2200 卡了()

其实就是 P1972 的加强版。每个位置记一个 \(p_i\) 表示 \(i\) 往前第 \(k\) 个与 \(a_i\) 相同的位置,没有则为 0。然后这个问题就变成了统计 \([l,r]\) 中有多少个 \(p_i<l\) 的位置,维护的信息就具有可减性了,直接上主席树解决。

CF213E. Two Permutations

差点忘了一个排列在值域上是连续的()

考虑 \(x=0\) 的情况。此时我们可以把 \(b_i\in[1,n]\) 的所有 \(b_i\) 拿出来,看他们构成的新序列与 \(a\) 是否相同。发现 \(a_i+x\) 在值域上是连续的一段,每次 \(x\) 增加时只用删除一个数加入一个数,于是可以线段树动态维护一下 hash 值。

CF348C. Subset Sums

一眼根号分治,难绷的是没有想到怎么快速求交,令人感叹。

\(siz\le \sqrt{n}\) 的集合记作轻集合,剩下的记作重集合。轻集合大小小,重集合个数少。考虑预处理每个重集合和每个集合的交,这个可以 \(\mathcal{O}(n\sqrt{n})\),直接枚举重集合和另一个集合,需要快速判断一个数在不在一个重集合里,直接对每个重集合开个数组即可。

预处理出来重集合和集合的交之后就很简单了,随便做一下就行。

CF580E. Kefa and Watch

哎,感觉自己越来越蠢了。一个循环节的条件不就是 \(a_i=a_{i-d}\) 嘛,你直接查询 \([l,r-d]\)\([l+d,r]\) 是否相同即可。

CF992E. Nastya and King-Shamans

三种做法。

第一种就是注意到当 \(a_i>0\) 时,满足 \(a_i-s_{i-1}\ge 0\) 的位置只会有 \(\log A\) 个,原因显然。线段树维护区间内 \(a_i-s_{i-1}\) 的最大值,暴力 dfs 即可。满足 \(a_i-s_{i-1}\ge 0\)\(a_i=0\) 的位置只会是一段前缀的 0,容易发现这样复杂度也是对的。

第二种就是考虑根据 \(a_i\) 的最高二进制位对数字分组,发现只有每组下标最小的两个位置可能成为答案。如果每次都用 bit 直接计算是 \(\log n\log A\) 的,可以存下来每次 \(\mathcal{O}(1)\) 修改,对两个有影响的组进行暴力重构,总复杂度 \(\mathcal{O}(q(\log n+\log A))\)

第三种是分块。可以去看洛谷题解。

CF1887C. Minimum Array

被卡空间了。

一个原始的想法是维护每个版本的哈希值,比较字典序的时候二分出第一个不同的位置直接比较。注意到这样算出来空间至少需要 200MB,而且复杂度也是很慢的 \(n\log^2 n\),过不了一点。

考虑优化。假设当前版本为 \(i\),之前得到的最小版本是 \(j\)。注意到如果我们能维护只执行了第 \(j+1\) 到第 \(i\) 次间的操作的数组 \(b\),如果 \(b\) 第一个不为 0 的位置 \(<0\),说明 \(i\)\(j\) 更优。注意到 \(b\) 第一个不为 0 的位置小于 0 等价于 \(b\) 的差分数组上第一个不为 0 的位置小于 0,于是可以用 map 直接维护差分数组,更新的时候清空就行。

CF1553F. Pairwise Modulo

可以看 这篇博客

CF1093E. Intersection of Permutations

我玩原神吗?

因为 \(a,b\) 都是排列,考虑对所有 \(b_i\) 找到它们在 \(a\) 中对应的位置,记作 \(p_i\),那么问题变成询问有几个 \(i\in[l2,r2]\) 满足 \(p_i\in[l1,r1]\),上个分块套值域分块做完了,复杂度 \(\mathcal{O}((n+m)\sqrt{n})\)。注意空间不要爆。

还有很多做法,懒得写了。

CF1916E. Happy Life in University

我玩原神吗???

当前在 \(u\),维护 \(u\) 子树内每个点 \(v\)\(diff(u,v)\)。注意到这个东西就是先区间加,然后从 \(u\) 开始往下 dfs,找到第一个 \(a_u=a_v\)\(v\) 就把 \(v\) 子树区间减,然后返回。一个点最多减一遍,所以复杂度 \(\mathcal{O}(n\log n)\)

dp

CF643C. Levels and Regions

有点东西,但不多,就不单独写了。

\(i\) 的概率是 \(p_i=\dfrac{t_i}{\sum\limits_{x=l_j}^it_x}\),期望次数 \(c_i=\sum\limits_{j\ge0}(1-p_i)^j\cdot p_i\cdot (j+1)=p_i\sum\limits_{j\ge0}(1-p_i)^j(j+1)\)

\(s=\sum\limits_{j\ge0}(1-p_i)^j(j+1)\),则 \((1-p_i)s=\sum\limits_{j\ge0}(1-p_i)^{j+1}(j+1)=\sum\limits_{j\ge1}(1-p_i)^jj=\sum\limits_{j\ge0}(1-p_i)^jj\)。又令 \(t=\sum\limits_{j\ge0}(1-p_i)^j\),则 \((1-p_i)t=\sum\limits_{j\ge1}(1-p_i)^j\)\(t=(1-p_i)t+1\)\(t=\dfrac{1}{p_i}\)。即 \(s=(1-p_i)s+\dfrac{1}{p_i}\)\(s=\dfrac{1}{p_i^2}\)\(c_i=p_i\cdot s=\dfrac{1}{p_i}=\dfrac{\sum\limits_{x=l_j}^it_x}{t_i}\)

现在题目转化成了把原序列分成 \(k\) 段,求最小代价和。令 \(s_i=\sum\limits_{j=1}^it_j\),写成转移大概就是 \(f_i=\min\limits_{j=0}^{i-1}\left\{f_j+\sum\limits_{k=j+1}^i\dfrac{s_k-s_j}{t_k}\right\}\)。这个东东可以维护个下凸壳斜率优化一下。因为 \(t_i\ge1\),可以发现斜优的 \(k,x\) 都是单增的,时间 \(\mathcal{O}(nk)\)

CF833B. The Bakery

\(f_{i,j}\) 表示把前 \(j\) 个分成 \(i\) 段的价值,转移 \(f_{i,j}=\max\limits_{p=0}^{j-1}\left\{f_{i-1,p}+\text{count}(p+1,j)\right\}\),可以用线段树维护那一坨东西。

\(\text{count}(p+1,j)\) 这个会变,怎么办?发现当 \(\text{count}(p+1,j-1)\gets \text{count}(p+1,j)\) 时,记 \(a_j\) 在序列中上一次出现的位置为 \(x\)(没出现过就为 0),只有在 \([x,j-1]\) 这个范围内的值会 +1。


哈哈,现在我会新做法了。因为这个玩意是满足四边形不等式的,有决策单调性,可以直接分治。对于 \(\text{count}\),可以主席树,也可以莫队。容易证明莫队的复杂度是对的。

CF1585F. Non-equal Neighbours

可以看 这篇博客

CF486D. Valid Sets

比较简单,但我不会去重。

显然你要枚举这个联通子图的最大点,但是这样有多个最大点的话会被多算。对于所有最大点,考虑强制钦定编号最小的为最大点,就不会算重了。

CF1841C. Ranom Numbers

其实可以贪,但我不会。

先反转一下字符串,定义 \(f_{i,j,0/1}\) 表示考虑前 \(i\) 位,最大值为 \(j\),改了/没改的答案。可以 \(\mathcal{O}(n)\)

CF1710C. XOR Triangle

感觉非常简单啊,不懂为什么是 2500。从高到低考虑每一位怎么填,状态记三维表示对于 \(a\oplus b,b\oplus c,a\oplus c\) 是否已经小于另两个数之和,数位 dp 一下即可。

图论

CF1483D. Useful Edges

有一点东西。

一条边 \((x,y,w)\) 是 useful 的条件是存在 \(u,v\),满足 \(\text{dist}(u,x)+w+\text{dist}(y,v)\le l_{u,v}\)。我们可以枚举 \(u,y\),求出最大的 \(l_{u,v}-\text{dist}(y,v)\),再枚举 \(x\) 判断即可。

比较有启示的是枚举四个点的顺序,有点没想到。以为枚举两个不相邻的点没有具体信息不好做,但其实想到之后还是觉得思路挺自然的。

CF416E. President's Path

一种神必做法。

先用 floyd 求一下全源最短路。定义 \(d_{s,t}\) 表示 \(s,t\) 之间的最短路,那么题目求的就是有多少条边 \((u,v,w)\) 满足 \(d_{s,u}+w+d_{v,t}=d_{s,t}\)。直接枚举是 \(\mathcal{O}(n^4)\) 的,我们考虑优化一下枚举的顺序。

枚举 \(s,v\),现在式子中的每一项都与且仅与 \(s,t\) 中一个有关。移项一下,得到 \(d_{s,u}+w=d_{s,t}-d_{v,t}\)。先把所有的 \(d_{s,u}+w\) 算出来,再枚举 \(t\),求刚刚算出来的东西中等于 \(d_{s,t}-d_{v,t}\) 的有多少个。

用 map 实现是 \(\mathcal{O}(n^3\log n)\) 的,会 T。理论上 unordered_map 是哈希表,随机数据均摊 \(\mathcal{O}(1)\),应该不会超时,但是它确实 T 了。(或许手写哈希表可以过,但我没试)

怎么办?我们利用哈希的思想,把这两项对一个大质数取模,这样就可以丢到桶里统计答案了。时间复杂度 \(\mathcal{O}(n^3)\)

CF567E. President and Roads

感觉自己降智严重,像个 nt。

先求出 \(s,t\) 到每个点的最短路。如果对于一条边 \((u,v,w)\)\(\text{dist}(s,u)+w+\text{dist}(v,t)>\text{dist}(s,t)\),则 \((u,v,w)\) 一定不是最短路上的边,边权变成 \(\text{dist}(s,t)-(\text{dist}(s,u)+\text{dist}(v,t))-1\) 即可。我们重点说怎么判断一条边可能/一定成为最短路上的边。

在跑最短路的时候顺便求一下 \(cnt_i\) 表示起点到 \(i\) 的最短路条数。如果一条边一定是最短路上的边,那么一定有 \(\text{cnt}(s,u)\times \text{cnt}(v,t)=\text{cnt}(s,t)\)\(cnt_i\) 可能会非常大,存不下怎么办?随便找个质数取模,哈希一下即可。

CF960F. Pathwalks

定义 \(f_{i,j}\) 表示以 \(i\) 点结尾,最后一条边权值为 \(j\) 的最长路。如果你按照时间戳加边,就可以满足编号递增。这个东西可以动态开点线段树维护,但是这并不是最妙的做法。

我们对每个点开一个 map 存转移,每次就是求在小于 \(w\) 的所有转移中最大的那个。看上去我们好像要区间查,但是我们可以发现,\(j\) 最大的转移一定最优,取 lower_bound 的前驱即可。

CF1037E. Trips

现在才会()

正着加边比较困难,考虑倒着删边。在删的过程中如果一个点度数小于 \(k\),说明这个点一定不可能成为答案,可以把它删掉,然后按照类似拓扑排序那样 bfs 一下,最后剩下的点集一定是极大的,大小就是答案。时间复杂度 \(\mathcal{O}(n+m)\),注意不要重复删边、点。

交互

gym100851J. Jump

可以看 这篇博客

贪心

CF351E. Jeff and Permutation

感觉如果不看 tag 的话想不到是贪心啊()

\(a_i\gets |a_i|\)。考虑绝对值最大的那个数 \(a_i\),如果他是正的,则右边的 \(a_j\neq a_i\) 他产生逆序对,否则左边的 \(a_j\neq a_i\) 会和他产生逆序对。于是我们可以贪心的选择这个数的正负性,然后把他删掉。此时跟他有关的逆序对已经被考虑完了,所以这么贪是对的。对于绝对值相同的情况,我们完全可以不用管它。因为最终它们的决定一定是左边一段为负,剩余一段为负,所以绝对值相同的数间是不会产生逆序对的。

CF436E. Cardboard Box

做法很多的反悔贪心题。

考虑反悔贪心。每次增加一颗星星时,我们有四种可能的选法:\(0\to 1\)\(1\to 2\)\(0\to 2\)\(2\to 1\)\(0\to 2\)\(1\to 0\)。所以我们开 5 个堆,维护一下上面涉及到的选法即可。复杂度 \(\mathcal{O}(n\log n)\)

考虑另一种反悔方法。首先有一个错误的暴力,就是把 \(a_i\) 丢进去,如果一个 \(a_i\) 被选了就把 \(b_i-a_i\) 丢进去。发现这样做错的原因在于我们不知道是选一个 \(b\) 还是两个 \(a\) 最优。考虑开两个优先队列 \(q_a,q_b\),每次取出 \(q_a\) 中最小两个值 \(a_1,a_2\)\(q_b\) 中最小值 \(b_1\),如果 \(a_1+a_2\le b_1\) 说明选两个一更优,答案加上 \(a_1+a_2\),如果这两个位置是第一次选还需要在 \(q_b\) 中删掉这两个位置,并在 \(q_a\) 中加入 \(b_i-a_i\);否则在 \(q_a\) 中删去 \(b_1\) 的位置,答案加上 \(b_1\)。选的个数是奇数时可以看成额外加入了一个 \(a=0,b=\inf\) 的物品。好像在 \(w=2n\) 时需要特判,不然会 re。

考虑另一种不用反悔贪心的做法。先把原数组按 \(b_i\) 从小到大排序。假设最后一个选两个的位置为 \(p\),发现 \(p\) 之前的位置至少选一个,\(p\) 之后的位置至多选一个。后者显然,前者是因为如果 \(p\) 之前存在不选的位置,你把那个位置选上 2,\(p\) 变成 0 会更优。所以可以枚举 \(p\),相当于在前面的 \(b_i-a_i\) 和后面的 \(a_i\) 中选 \(m-p\) 个,可以值域线段树上二分。复杂度 \(\mathcal{O}(n\log n)\)

CF1889B. Doremy's Connecting Plan

突然就想通了()

发现所有的都尽量和 1 合并即可,考虑反证法。假如现在 \(i,j\) 之间可以合并,但 \(i,j\) 都不能和 1 合并。那么有 \(\dfrac{a_i}{c}+\dfrac{a_j}{c}\ge ij\),且 \(\dfrac{a_i}{c}+\dfrac{a_1}{c}<i\)\(\dfrac{a_j}{c}+\dfrac{a_1}{c}<j\)。代换可以得到 \(i+j-\dfrac{2a_1}{c}>a_i+a_j\ge ij\)。因为 \(i,j>1\),所以这是不可能的,所以我们贪心的把所有的往 1 合并即可。

字符串

CF1827C. Palindrome Partition

考虑 \(f_{i}\) 表示以 \(i\) 结尾的这样的串的个数。考虑转移,\(f_{i}=\sum_{j\le i}f_{i-j}\),其中 \(s[i-j+1\ldots i]\) 是一个偶回文串。那么这样就对了\(\ldots\)吗?

注意到这样完全不对捏,因为一个满足条件的串会被多种不同的划分方式算多遍,这就寄了。但是注意到我们只需要从最小的满足条件的 \(j\) 转移一下,所以问题变成求以 \(i\) 结尾的最短偶回文串的长度,大力 PAM 即可。复杂度 \(\mathcal{O}(n)\)

CF30E. Tricky and Clever Password

有点意思。注意到 suffix 的结尾是确定的 n,预处理 \(f_i\) 表示最大的 \(j\) 满足 \(s[i\ldots i+j-1]=\text{rev}(s[n-j+1\ldots n])\)。然后可以注意到注意到 middle 越长越好,正确性显然。考虑枚举 middle 的中心 \(i\),求最长回文半径 \(r\),然后二分 prefix 和 suffix 的长度 \(l\),那么合法当且仅当 \(\max\limits_{j=1}^{i-r-l}\{f_j\}\ge l\),复杂度 \(\mathcal{O}(n\log n)\)

构造

CF1158B. The minimal unique substring

为什么只有 2200?为什么只有 2200?为什么只有 2200?为什么只有 2200?为什么只有 2200?为什么只有 2200?

比较考验注意力的神秘构造。注意到这个 \(n\equiv k\pmod 2\) 肯定是有深意的,因为这样 \(\dfrac{n-k}{2}\) 就一定是整数了。记 \(t=\dfrac{n-k}{2}\),注意到我们如果把所有 \(i\bmod (t+1)\neq 0\) 的位置涂成 1,剩下的涂成 0,就恰好满足条件了捏。下面是证明。

先证存在长为 \(k\) 的只出现了一次的子串。我们把一段 \(111\ldots 0\) 称为一块,注意到从第一块的零处开始,往后长为 \(k\) 的一段只出现了一次,即 \(s[t+1\ldots t+k]\) 只出现了一次。因为开头是 0,所以如果还有第二次出现至少得从 \(2t+2\) 开始了,但是 \(2t+2+k-1=n+1\),刚好超出边界,于是寄了。

再证长度小于 \(k\) 的子串不会只出现一次。注意到对于一个子串 \(s[l\ldots r]\),如果 \(l>t+1\)\(s[l-(t+1)\ldots r-(t+1)]=s[l\ldots r]\),否则 \(s[l+(t+1)\ldots r+(t+1)]=s[l\ldots r]\)。此时 \(l\le t+1\)\(r-l+1<k\),则 \(r+(t+1)<l+k+t\le 2t+1+k=n+1\),于是一定有第二次出现。

杂题

CF1924C. Fractal Origami

感觉这个题对不会折纸的人很不友好啊,只能上手。

注意到对 \(n\le 4\) 的情况手玩一下可以发现峰线与谷线每次新增的长度相同,证明略。还可以注意到峰线长等于 \(\sum\limits_{i=1}^{n-1}2(\sqrt{2})^{i-1}\),谷线长为峰线长加 \(2\sqrt{2}\),于是直接算即可。

posted @ 2023-05-19 16:05  xx019  阅读(21)  评论(0)    收藏  举报