AtCoder Beginner Contest 233
A,B,C 略过。
D
求有多少个二元组 \((l,r)\) 满足 \(\displaystyle \sum_{i=l}^{r} A_i=K\)。
先求出前缀和,记为 \(s_i\),那么要求就是 \(s_r-s_{l-1}=K\),移项一下 \(s_{l-1}=s_r-K\),那么考虑统计 \(s_r-K\) 的数量,最后将所有 \(l\) 加起来。
代码
E
求 \(\displaystyle \sum_{k=0}^\infin \lfloor \dfrac{X}{10^k} \rfloor\) 的值。
列竖式模拟一下,发现相当于每次向左移动一位,然后加起来,最后往上进位。
然后求不进位的值的时候,每一位都是前缀和。
代码
F
给定一个长度为 \(n\) 的排列 \(P\),同时给出 \(m\) 个操作 \((a_i,b_i)\),可以把 \(P_{a_i}\) 和 \(P_{b_i}\) 交换,判断是否能构造一组操作次数不超过 \(5 \times 10^5\) 步的操作序列使得 \(P\) 变为升序。
初看难以入手,直接的判断似乎很麻烦,那么考虑往图的方向想。
\(m\) 个操作可以抽象成一个图,那么如果 \(P_i\) 和 \(i\) 不在同一个连通块,那么一定不能拍成升序,所以可以用并查集判断一下。
那么考虑构造方案,因为直接冒泡排序的次数是 \(999+998+\cdots +1=499500\),所以随便建出一个生成树,然后从度数为 \(1\) 的点开始交换并删点就好了。
代码
G
给定一个 \(n\times n\) 的网格图,有若干个格子有障碍。每次可以选择一个 \(d\times d\) 的区域然后消耗 \(d\) 点体力将其中的障碍消去。问将所有障碍消去的最小体力消耗。
考虑一个子问题 \(m\times n\) 的网格,那么消掉这里的障碍至多要 \(\max(m,n)\) 的体力,中间有可能会有空行或者空列,那么可以把这个网格沿着空行或者空列切开,转化成更小的子问题。
那么记 \(f_{i,j,k,l}\) 表示左上角 \((i,j)\) 右下角 \((k,l)\) 的最小消耗,记搜转移即可。
代码
Ex
平面上给定 \(n\) 个点,\(q\) 个询问,每次询问到点 \((x_i,y_i)\) 的第 \(k\) 近的曼哈顿距离。
\(1 \leq n \leq 10^5\),\(1 \leq q \leq 10^5\),时限 \(\texttt{7s}\)。
口胡一下,曼哈顿距离的第 \(k\) 小难以解决,因为有绝对值,然后两个维度。
那么考虑一个小技巧,将每个点变成 \((x+y,x-y)\),这样曼哈顿距离就转化成切比雪夫距离。
于是每次询问我们二分答案,然后查询有多少点到询问点的距离小于等于二分的答案,这样就做一个查询矩形和,主席树维护一下。
代码不想写,咕了。