51 CSP-S 模拟赛32
1 得分
题目 | T1 | T2 | T3 | T4 | 总分 |
---|---|---|---|---|---|
得分 | \(4\) | \(20\) | \(11\) | \(27\) | \(62\) |
排名:rank \(9\)。
真正炸裂的一集。
2 题解
T1
考虑到边数较少,于是考虑能不能枚举边相关信息。通过部分分可以有如下讨论:
- \(c_u\ne c_v\) 时,意味着原先两点间有的边没了,那么两端的两个点只能选其一。
- \(c_u=c_v\) 时,意味着原先两点间没有边有了,那么这一条边可选可不选。
于是发现每一条边的决策只有两种,而边数 \(K\) 只有 \(20\),所以可以 \(O(2^K)\) 枚举边的状态。
接下来判断选择的边是否有冲突,以及每一个岛屿上选的边能不能构成完全图即可。
T2
首先考虑没有吃糖果变胖的机制,我们怎么走可以使初始体重最大。这就是经典问题 [货车运输],显然走的路径一定是最大生成树上的路径。
那么有了这个机制这个性质也不会变,所以考虑在最大生成树基础上求解。又由于这是边权问题,考虑 Kruskal 重构树来解决。对于单次合并的两个子树 \(u,v\),设其子树权值和为 \(s_u,s_v\),子树本身最大答案为 \(a_u,a_v\),连接两子树边权为 \(w\)。
那么此时一定是先吃其中一颗子树,再吃另外一颗最优。假设先吃 \(u\),那么此时答案会变为 \(\min\{w-s_u,a_v-s_u\}\)。先吃 \(v\) 同理。
最后根节点的 \(a\) 即是答案。
T3
容易发现,整个给钱的过程就是将儿子从小到大填满,然后再一点点往父亲给。所以如果一个节点需要 \(k\) 的钱来填它的子树,那么子树权值和比 \(k\) 小的兄弟应该都被填满,其他的兄弟都应该填上 \(k\)。那么我们就可以知道它的父亲需要的钱是 \(\sum\min\{sum_x,k\}\)。
暴力跳的复杂度是 \(O(n^2)\),考虑优化。不难发现的是,如果在某一次跳的时候出现了 \(sum_x>k\) 的情况,那么 \(k\) 就会至少翻一倍。而 \(k\) 最多就是 \(V=\sum v_i\),所以出现上述情况的次数不超过 \(\log V\)。
考虑从这里入手,我们把这样的节点称为关键点,然后利用倍增求出每一个点跳到下一个关键点的价值和以及需要多少钱才能跳到该关键点。这样复杂度就是 \(O(n\log V)\) 的了。
T4
讲得比我清楚。
52 CSP-S 模拟赛33
1 得分
题目 | T1 | T2 | T3 | T4 | 总分 |
---|---|---|---|---|---|
得分 | \(100\) | \(100\) | \(50\) | \(25\) | \(275\) |
排名:rank \(3\)。
2 题解
T1
直接上并查集。对于一组 \((x,y,z)\),我们将 \(x+i\) 与 \(y+i\) 连边,同时标记 \(x+z\) 与 \(y+z\) 要不同。求答案的时候从头开始贪心,求出冲突的集合中已经确定了的值,求出这些值的 \(\text{mex}\) 就是当前答案。
T2
超级大水题,先 BFS 算出每个点与传送门的连通性,然后传递闭包算传送门之间连通性,最后查答案的时候枚举一下即可。上述过程全部可以 bitset
优化,复杂度 \(O(knm+\dfrac{k^3}{w}+\dfrac{qk^2}{w})\)。
T3
首先发现 \(p\) 两边的 \(l,r\) 互不影响,因此先求出前缀和,则只需要让 \(sa_r-ksb_r\) 与 \(-sa_l+ksb_l\) 分别最大即可。
发现上面两个式子都是 \(y=kx+b\) 的一次函数的形式,也就是说每一个位置都对应一条直线。而我们要求的就是再 \(x=k\) 处与所有直线交点的最大值。这个就是李超线段树的经典问题了。
当然我们需要先离线,然后边插入边查询即可。
T4
讲得很好。
53 CSP-S 模拟赛34
1 得分
题目 | T1 | T2 | T3 | T4 | 总分 |
---|---|---|---|---|---|
得分 | \(9\) | \(50\) | \(20\) | \(0\) | \(79\) |
排名:rank \(15\)。
依然炸裂的一集。
2 题解
T1
考虑从 \(k\) 处掰开序列,然后分别求前缀和。问题就转化为移动 \(l=r=1\) 两个指针,使得每一次的 \(s_l+s_r\) 都不大于 \(0\)。
考虑贪心。我们显然是每一次只将 \(l,r\) 中一个移到值更小的位置。但是这样只能将 \(l,r\) 分别移到最小值处。不过发现后面的移动倒过来和前面是一样的,所以倒过来再跑一边即可。
T2
首先要观察到每一次会至少删一半的数,所以有效的 \(k\) 只有 \(\log n\) 个。
发现去掉序列最大值后两边可以分开求解。设 \(dp(i,j,0/1,0/1)\) 表示序列长度为 \(i\),不超过 \(j\) 次操作就删到不能再删的序列方案数。后面的 \(0/1\) 表示左 / 右是有一个比该序列所有数都大的数还是没有。接下来我们只需要枚举最大值位置、两个子区间的状态即可,复杂度 \(O(n^2\log n)\)。
转移方程大致如下:
(dp[i][j][0][0] += dp[k - 1][j][0][1] * dp[i - k][j][1][0] % Mod * C[i - 1][k - 1] % Mod) %= Mod;
(dp[i][j][0][1] += dp[k - 1][j][0][1] * dp[i - k][j - 1][1][1] % Mod * C[i - 1][k - 1] % Mod) %= Mod;
(dp[i][j][1][0] += dp[k - 1][j - 1][1][1] * dp[i - k][j][1][0] % Mod * C[i - 1][k - 1] % Mod) %= Mod;
int x = (dp[k - 1][j][1][1] - dp[k - 1][j - 1][1][1] + Mod) % Mod;
int y = (dp[i - k][j][1][1] - dp[i - k][j - 1][1][1] + Mod) % Mod;
(dp[i][j][1][1] += (dp[k - 1][j][1][1] * dp[i - k][j][1][1] % Mod - x * y % Mod + Mod) % Mod * C[i - 1][k - 1] % Mod) %= Mod;
T3
我们建立两张图,一张是原图,另一张是反图。于是原问题就相当于从两张图的原点走到终点的费用和。
考虑二维 Dijkstra,设 \(dis(x,y)\) 表示第一张图走到 \(x\),第二张图走到 \(y\) 所用费用最小值,使用与 Dij 相同的转移方式即可。为了维护已走过的车站,再开一个 bitset
\(sta(x,y)\) 存此时走过的站点。转移时根据这个加上对应权值即可。
T4
显然使用扫描线,对于每一个区间维护当前覆盖该区间且删除时间最晚的矩阵,利用并查集更新即可。
具体还是看这里。