比赛记录(31~40)

31 CSP-S 模拟赛13

1 得分

题目 T1 T2 T3 T4 总分
得分 \(0\) \(20\) \(60\) \(0\) \(80\)

排名:rank \(12\)

2 题解

T1

考虑最小的数,显然它要放到最左边或者最右边,那么它要交换的次数就是它左边比它大的数的个数或者右边比他大的数的个数,两者取 \(\min\) 即可。

显然将最小的数删去后对于整个序列答案不会发生影响,因此用树状数组扫一遍即可,复杂度 \(O(n\log n)\)

T2

比较狗屎的一道题。

首先考虑设 \(dp(i,j)\) 表示第 \(i\) 次美食节后在坐标 \(j\) 的花费最小值。实际上,这个 dp 转移可以分为两部分:

  • \(dp(i-1,j)\) 更新 \(dp(i,j)\)\(j<l_i\) 就加上 \(l_i-j\)\(j>r_i\) 就加上 \(j-r_i\)
  • \(dp(i,j)+1\) 更新 \(dp(i,j-1),dp(i,j+1)\)

实际上,通过这两步操作,最后得到的 \(dp\) 数组一定满足一个性质:对于固定的 \(i\)\(dp(i,j)\) 的差分只可能是 \(-1,0,1\),且连续出现。显然差分为 \(0\) 的一段必为最小值,那我们就维护这一段差分为 \(0\) 的区间即可。

\(O(n)\) 扫一遍所有区间即可,注意分类讨论。

T3

设当前要查询 \(k\),令 \(b_i=\text{sgn}(a_i-k)\),那么我们肯定使用 \(0\) 去更新中间的 \(1,-1\)。考虑以 \(0\) 为界限分开每一个区间,这样我们实际上就是求区间两端为 \(0\)、中间为 \(1,-1\) 的答案。

不难发现,每一个位置都要进行一次操作,但是可能会产生额外的操作。具体的,对于一段连续的 \(1,-1\) 交替出现的区间 \([l,r]\),那么其需要的额外操作次数是 \(\lfloor\dfrac{r-l+1}2\rfloor\)。我们用线段树维护出连续的 \(1,-1\) 区间即可。

T4

直接粘波波题解了。

(实际上 \(dp_i\) 表示的是以点 \(i\) 为开头的最小代价)

32 CSP-S 模拟赛14

1 得分

题目 T1 T2 T3 T4 总分
得分 \(10\) \(30\) \(20\) \(0\) \(60\)

排名:rank \(24\)

考的最好的一集。

2 题解

T1

显然一次反转可以减少 \(1\)\(2\) 个逆序对,那么我们只需要统计出整个序列的逆序对个数 \(n\)。接下来由基础的博弈论知识可知:

  • \(n\)\(3\) 倍数时,后手必胜。
  • \(n\) 不是 \(3\) 倍数时,先手必胜。

T2

由于对 \(a_x\) 操作后 \(a_{x-1},a_{x+1}\) 永远不会大于 \(a_x\),因此操作总数一定是某些位置上的数的总和,并且之间仅相邻 \(1\)\(2\) 个数。

这样我们就可以考虑线段树了,我们考虑在合并时会出现的情况:

  • [..._X_X_]+[_X__X...]
  • [..._X_X]+[_X_X_...]
  • [..._X__]+[X_X_...]
  • [..._X_X]+[X_X_...]

容易发现上面三种情况都很简单,直接合并即可。但是最后一种情况比较难,我们必须要舍弃掉左右区间的端点,具体的应该根据原数组大小确定。那么在舍弃掉一个区间的端点后,我们的答案会发生变化,因此实际上我们需要维护的信息有:考虑左右端点的答案,不考虑左端点的答案,不考虑右端点的答案,两个端点都不考虑的答案。

同时为了判断中间是否会出现第四种情况,我们还需要维护上面四个情况下每一种情况的答案状态是否选了左端点或右端点。这样我们就能直接在线段树上求出答案了。

T3

首先考虑怎样组合零件最大,实际上是每次取两端。

然后发现贪心是具有正确性的,因此我们每一次要尽可能扩展右端点直到不能再扩展。

那么朴素做是 \(O(n^2)\) 的,考虑优化。我们采用倍增的方式可以轻松优化到 \(O(n\log ^2 n)\)

但是这样做其实是比较卡的,我们考虑另一种倍增的方式。容易发现上面每一次尝试扩展都要重新整个排一边序,复杂度有点高。如果我们已经扩展的序列是排好的了,那就只需要对新增加的序列进行排序然后归并即可。基于这种思路我们可以设计出这样的倍增:

  • 设当前左端点为 \(l\),已扩展的右端点是 \(r\),上一次扩展的长度是 \(p\)。此时我们尝试扩展 \(2\times p\),如果可以的话直接就将 \(r\) 赋成 \(r+2\times p\),更新 \(p\);否则就将 \(p/2\),然后再次尝试。

每一次只有扩展的时候才会排序,并且归并的复杂度是 \(O(n)\) 的,总复杂度 \(O(n\log n)\),十分优秀。

T4

首先连边跑出最短路,接下来不难发现我们的操作一定是在最短路图上进行的。那么我们就可以将所有铁路再拆成几段,每一段再最短路图上联通且原先位于同一条铁路上。此时考虑设 \(f_i\) 表示走到 \(i\) 的最大平方和,那么对于在新的同一段铁路上的点 \(j\),会有转移:

\[f_i=f_j+(dis_i-dis_j)^2 \]

显然可以直接斜率优化。那么我们对于每一段铁路开一个单调栈维护凸包即可。

最后我们还需要考虑一下枚举顺序,实际上由于该图没有负权边,\(dis\) 更小的拓扑序一定更小,因此按 \(dis\) 排序然后 dp 即可。

33 CSP-S 模拟赛15

1 得分

题目 T1 T2 T3 T4 总分
得分 \(30\) \(-\) \(0\) \(30\) \(60\)

排名:rank \(19\)

第一次连代码都没交的题!

2 题解

T1

运用注意力加上一点点直觉可知,答案就是 \(\max\{a_i\}\)\(\lfloor\dfrac{\sum a_i}{m}\rfloor\) 取最大值。

T2

直接拆式子即可,这里就不讲了。

T3

首先发现打比赛的涨分过程实际上可以分为几段,每一段都是当前较小的超过当前较大的。

那么我们就可以设 \(f(i,j)\) 表示当前号分数为 \(i\),第一次超过自己到达了 \(i+j\) 的答案。注意这里的答案是要同时维护概率和期望的。这一部分实际上可以由之前的部分推出,不难想到可以枚举第一次跳的步数 \(k\),然后通过 \(f(i+k,*)\) 转移即可。但是此时会有两个问题:

  • \(k=0\) 时两边都有 \(f(i,j)\)
  • 只枚举第一次跳的步数有些局限。即我们无法单纯通过 \(f(i+k,*)\) 转移。

第一个问题很简单,我们只需要解方程就行。对于第二个问题,我们可以这样解决:考虑再设一个 \(t(j)\) 表示从 \(i\) 走到 \(i+j\) 的答案,我们利用 \(f\) 数组进行 dp 求出 \(t(j)\)。然后再利用 \(t(j)\) 求出 \(dp(i,j)\) 即可。

最后我们再设 \(g(i,j)\) 表示大号分数为 \(i\),小号分数为 \(j\) 的答案,这一部分直接利用 \(f\) 数组计算即可。

T4

显然只有 \(\gcd\) 相同的区间才能选,那么不妨考虑枚举当前的 \(\gcd\)。同时设 \(f(i)\) 表示此时在前 \(i\) 个数中选择区间的方案数。显然如果这样做的话我们必须要知道对于每个 \(i\),可以分割出多少 \(\gcd\) 相同的左端点区间。这个直接使用 ST 表 + 二分就可以求出。

现在我们就得出了很多形如 \((l,r,p,d)\) 的东西,表示 \(\forall j\in [l,r],\gcd(j,i)=d\)。那么若 \(d\) 等于当前枚举的 \(\gcd\),则会有转移方程:

\[f(i)(i\in [r,n])\ +\!\!=\sum_{j=l}^r f(j-1) \]

同时我们考虑设 \(g(i)\) 表示后 \(i\) 个数中选区间的方案数。与 \(f(i)\) 的处理是一致的。

不难发现两个数组只需要执行区间求和、区间加操作,考虑用线段树维护。

现在考虑求出 \(i\) 的答案,考虑容斥。所有区间任选的方案是 \(f_n\),而没有 \(i\) 的方案数是 \(f_{i-1}g_{i+1}\)。但是如果每一次都暴力增加答案的复杂度会炸。考虑到如果一个 \(i\) 没有作为 \(r\) 出现,那么一定有 \(f(i)=f(i-1)\)。因此两个端点 \(r_1,r_2\) 之间增加的贡献是相等的,考虑差分维护即可。复杂度是 \(O(n\log w)\) 的。

34 CSP-S 模拟赛16

1 得分

题目 T1 T2 T3 T4 总分
得分 \(100\) \(100\) \(20\) \(13\) \(233\)

排名:rank \(2\)

2 题解

T1

可以得到如下模型:

  • 首先显然 \(n\) 是答案。
  • 考虑将 \(i\) 之前的字符串翻转,然后考虑两端的字符串是否相等,同时计算延伸到的右端点 \(r\)。如果两端字符串相等且 \(r\) 也是合法答案,那么 \(i\) 就是合法答案。

判字符串相等直接用哈希即可,不过你用 Manacher 我也没意见。

T2

大分类讨论题。首先发现答案只可能是 \(0,1,2,3\)​。

  • 若整个序列已经有序,答案为 \(1\)

  • \(1\) 右边有数字。

    • 如果存在一个位置 \(i\),使得 \(p_i=i\),且 \(p_1,p_2,\cdots p_{i-1}\) 出现了所有 \(1,2,\cdots,i-1\) 的数,答案为 \(1\)
    • 否则,答案为 \(2\)
  • \(1\) 右边没有数字(即 \(p_n=1\))。

    • \(a_1=n\),那么必须要 \(3\) 次才能将两者全部返回原位,答案为 \(3\)
    • 否则,答案为 \(2\)

T3

首先我们只去考虑一个左端点做出的贡献,显然就是每一次扩展右端点,然后去更新当前的最大最小值,并单次累加答案。

换句话讲,我们可以对当前的左端点维护两个变量,分别代表从该左端点到当前右端点的最大值和最小值,同时我们还需要在每一次更新后维护出最大值和最小值的乘积 \(f\),那么当前左端点做出的贡献就是 \(f\) 的历史和。

现在考虑对于所有左端点如何维护,显然需要开两个数组维护每个左端点到当前右端点的最大值和最小值,同时单次维护两者乘积以及历史和。考虑最大(小)值怎样维护,可以利用单调栈求出当前数字能扩展到的最靠左的位置,那么当扩展到该端点的时候就会对这个区间进行最大(小)值的覆盖。

所以实际上我们要实现的操作是:区间覆盖最大(小)值、查询最大最小值乘积的历史和。这个可以直接上线段树维护。具体的,我们要维护的信息有:最大值之和、最小值之和、最大最小值乘积之和、最大最小值乘积历史和。懒标记需要维护覆盖信息和其他的系数标记。

T4

我们对操作进行分块,对每一个块中的询问和修改处理即可。考虑设块长为 \(S\),那么先考虑修改。显然在当前块之前的修改可以直接全部暴力修改掉,然后就只需要考虑块内的修改。容易发现此时修改就只剩下 \(S\) 个了。

不难发现,对于原先的 \(m\) 条边,会有很多边不需要考虑修改。那么我们就可以动态插入维护。那么为了方便起见,我们可以将所有询问按照重量从大到小排序,同时将所有边按承重也从大到小排序,这样我们每换一次询问就将合法的边插入并查集进行维护即可。

现在考虑本块内需要修改的边,我们可以暴力查看当前块内的 \(S\) 个修改,如果在当前询问之前切合法就插入并查集,处理完这个询问之后再将这些边删去即可。那么这样的话就需要用到可撤销并查集了。

时间复杂度是 \(O(\dfrac QS m\log m+\dfrac QS S^2\log n)\)。也就是 \(O(\dfrac{Qm\log m}S+QS\log n)\)。取 \(S=\sqrt{m\dfrac{\log m}{\log n}}\) 得到理论最优,但是由于并查集的复杂度并没有 \(\log n\),所以实际上取 \(S=\sqrt{m\log m}\) 最优。

35 CSP-S 模拟赛17

1 得分

题目 T1 T2 T3 T4 总分
得分 \(100\) \(100\) \(10\) \(10\) \(210\)

排名:rank \(1\)

2 题解

T1

发现是子序列问题,考虑设 \(dp(i,j)\) 为两个序列分别枚举到 \(i,j\) 位时的最大长度。那么转移就是:

\[dp(i,j)=\max_{k<i,l<j,a_i\mid a_j}\{dp(k,l)\} \]

显然过于不优。考虑设 \(f_j=\max\limits_{k<i}(dp(k,j))\),每次查询完 \(i\) 的 dp 值后动态更新即可。那么转移就是:

\[dp(i,j)=\max_{l<j,a_i\mid a_j}\{f(j)\} \]

显然只需要维护 \(f(j)\) 的前缀最小值即可。而每次得出 \(dp(i,j)\) 后又要动态更新,所以还要单点修改最大值。显然考虑树状数组。那么剩下的就是枚举 \(i,j\) 的复杂度了。实际上根据调和级数相关知识可知,这一部分的复杂度是 \(O(n\log n)\) 的,总复杂度就是 \(O(n\log ^2 n)\)

T2

说了一堆废话,实际上就是求区间众数的出现次数。回滚莫队 / 普通莫队 / 分块都可以做,复杂度均为 \(O(n\sqrt n)\)

T3

考虑到重排后形成回文串的条件就是出现了的字符的出现次数均为偶数或只有一个奇数。那么可以想到利用二进制表示,合法方案就只有 \(23\) 种。

然后考虑怎样得出任意两点间的二进制串。设 \(str(i)\) 表示从根节点到 \(i\) 形成的二进制串,那么 \(str(u)\oplus str(v)\) 就是两点间二进制串。

对于每一个节点,暴力枚举子树内两个点,具体做法就是用一个桶 \(t(i)\) 存储当前其他子树内 \(str(x)=i\) 的最深的节点 \(x\) 的深度,然后暴力枚举当前子树中的点,与其他子树中的点构成一条路径,然后判断更新即可。复杂度 \(O(23n^2)\)

考虑优化,使用 dsu on tree,将重儿子的 \(t\) 数组直接继承,复杂度可以做到 \(O(23n\log n)\)

T4

36 CSP-S 模拟赛18

1 得分

题目 T1 T2 T3 T4 总分
得分 \(80\) \(50\) \(10\) \(70\) \(210\)

排名:rank \(1\)

2 题解

T1

首先将所有边复制一遍,然后问题可以转化为:从图中删去两条不重复的边,原图是否存在欧拉路径。

根据图论相关知识可知,只有三种情况可以使得新图存在欧拉路径:

  • 删去有公共顶点的两条边。
  • 删去一个自环和任意一条边。
  • 删去任意两个自环。

简单计算以下即可。注意需要特判边不联通的情况。

T2

考虑原题实际上是求最大的 \(d\),满足:

\[\sum (d\lceil\dfrac{a_i}{d}\rceil-a_i)\le k \]

移项后就是:

\[d\times\sum\lceil\dfrac{a_i}{d}\rceil\le k + \sum a_i \]

\(C=k+\sum a_i\),则可得:

\[\sum\lceil\dfrac{a_i}{d}\rceil\le\lfloor\dfrac Cd\rfloor \]

显然右边的式子可以利用数论分块求出每一段的值以及右端点。考虑到 \(d\) 最大的之后左边会更小,因此一定会更优,所以只需要判断当前右端点是否可行即可。

T3

状态很奇妙。设 \(dp(i,j)\) 表示在一颗 i - 超级树内选出 \(j\) 条互不相交的路径的方案数,则答案为 \(dp(k,1)\)。只要能想出这个状态转移就不难了。但是看似 \(j\) 需要枚举到 \(2^k\),实际上只需要枚举到 \(k\) 就行。

T4

37 CSP-S 模拟赛19

1 得分

题目 T1 T2 T3 T4 总分
得分 \(100\) \(25\) \(0\) \(0\) \(125\)

排名:rank \(4\)

2 题解

T1

数据比较难卡,所以会有很多奇怪的做法可以通过。

考虑到这原序列的子串如果要满足条件,那么长度一定不超过 \(\log_2 10^{18}\approx 60\)(除公比为 \(1\) 外),那么我们从每一个位置开始枚举,复杂度不会超过 \(O(60n)\)。那么现在考虑怎样枚举。

假设当前枚举 \(i\),那么考虑 \(a_{i+1}\)\(a_i\)。若二者没有倍数关系,那么直接结束。否则计算出两者的比 \(s\),对它进行质因数分解 \(s=p_1^{q_1}p_2^{q_2}\cdots p_{m}^{q_m}\),然后考虑计算该数列的最小公比。实际上,我们只需要求出 \(g=\gcd(q_1,q_2,\cdots,q_m)\),然后最小公比就是:

\[k=p_1^{\frac{q_1}g}p_2^{\frac{q_2}g}\cdots p_m^{\frac{q_m}g} \]

然后我们就只需要看后面的数字与当前 \(a_i\) 的比是否是 \(k\) 的整数次幂即可。注意判重复数字。

T2

20 pts:暴力直接求解出每种情况的概率和方案,然后算期望即可。

another 10 pts:直接上链性质即可。

another 5 pts:显然菊花答案是 \(1\)

100 pts

根据第一档暴力可知,我们可以通过概率乘贡献的方式来计算。那么设 \(f(i,j)\) 表示根节点为 \(i\),子树内的点到 \(i\) 的轻链个数的最大值为 \(j\) 的概率。首先枚举当前重儿子,然后再枚举当前儿子,最后枚举轻链个数。这样做复杂度是 \(O(n^3)\) 的,考虑优化。

我们发现,当我们枚举到一个儿子 \(v\) 时,如果 \(j>siz_v+1\) 就是无意义的,因此我们只需要枚举到 \(siz_v+1\) 即可,复杂度 \(O(n^2)\)

T3

首先考虑要求的图实际上就是所有 \(n\) 标号联通欧拉图的个数再乘上 \(C_n^2\)。因为对于任意一张欧拉图,我们选择其中任何一条边,将其状态改变,一定可以得到一张满足要求的图且不重不漏。那么现在就是要求 \(n\) 标号联通欧拉图数量。

考虑先求出 \(n\) 标号的满足所有点度数为偶数的图的个数。我们可以先任意连前 \(i-1\) 个点,然后将其中度数为奇数的点连接第 \(i\) 个点,这样一定可以得到满足要求的图。即:

\[g_i=2^{C_{i-1}^2} \]

现在考虑 \(n\) 标号联通的欧拉图数量 \(f_i\),我们可以考虑用 \(g_i\) 去减。实际上,我们可以枚举 \(1\) 所在联通块大小,钦定剩下的点与该联通块都不联通即可。即:

\[f_i=g_i-\sum_{j=1}^{i-1}C_{i-1}^{j-1}f_jg_{i-j} \]

那么答案就是 \(f_n\)

T4

首先显然考虑从高位向低位贪心,但是这要求我们需要维护出树上位运算的信息。由于位运算不满足交换律,所以我们只能对树上的路径进行直接维护。那么就考虑利用树链剖分和线段树。

现在考虑到我们要求的是树上两点间的信息,这显然会分成两段,即 \(u\to lca,lca\to v\)。显然这两段在线段树上分别是从右往左和从左往右的,因为位运算没有交换律,所以我们必须把这两者分开维护。

具体的,我们在线段树上的区间维护 \(f(0/1,0/1)\),第一维表示从左 / 从右放,第二维表示放的是 \(0\) / \(1\),经过该区间的操作后得到的数。如果我们对二进制上的每一维去维护这个值然后贪心,复杂度是 \(O(nk\log ^2n)\) 的,无法通过。

考虑到实际上将每一位分开维护是完全不必要的,我们可以直接将所有的位合起来处理,这样复杂度就是 \(O(n\log^2n)\) 的,可以通过。

具体的合并代码如下:

Node merge(Node x, Node y) {
	Node ans;
	ans.l0 = (x.l0 & y.l1) | ((~x.l0) & y.l0);
	ans.l1 = (x.l1 & y.l1) | ((~x.l1) & y.l0);
	ans.r0 = (y.r0 & x.r1) | ((~y.r0) & x.r0);
	ans.r1 = (y.r1 & x.r1) | ((~y.r1) & x.r0);
	return ans;
}

38 CSP-S 模拟赛20

1 得分

题目 T1 T2 T3 T4 总分
得分 \(100\) \(60\) \(20\) \(20\) \(200\)

排名:rank \(2\)

2 题解

T1

发现饼干数远小于天数,也就是说实际上能给饼干的天数不多,可以考虑枚举这样的天数的个数。考虑利用 dp,设 \(dp(i,j)\) 表示花 \(i\) 天放 \(j\) 个饼干,且每天放置的饼干个数 \(\in [1,m)\) 的方案数。那么转移方程就是:

\[dp(i,j)=\sum_{k=1}^{m-1}dp(i-1,j-k) \]

发现后面可以上前缀和优化,复杂度就是 \(O(n^2)\) 的。最后答案就是 \(\sum dp(i,n)\times C_{D}^i\)

T2

60 pts

考虑到我们可以枚举最小环上离终点最近的点,那么实际上就相当于先将 \(1\) 号点与该点连边断开,再求出此时从 \(1\) 号点到该点的最短路,最后再将删去的边权加上即可。那么这样暴力做是 \(O(n(n+m)\log n)\) 的。

100 pts

考虑到我们可以将所有与 \(1\) 相连的点划分为两个点集,接下来人为规定一个点集只有来自 \(1\) 的入度,另一个点集只有指向 \(1\) 的出度,此时再跑最短路就能求出当前最小环。

接下来考虑怎样求整体最小环。我们发现,如果真正答案对应的起点和终点(除 \(1\) 以外的部分)分别处于两个点集中,那么一定就可以得到最终答案。考虑两个点的编号一定不同,因此一定有一位二进制不同,就考虑利用二进制分组建图。具体的,枚举每一个二进制位,然后将该位按照 \(0/1\) 划分跑最短路,求出的最小的答案就是最小环。

T3

首先根据 2024.7.25 T3 可知,对于这种两个点只能选其一的限制,考虑对两点之间连边。具体来讲,我们从当前的背面向正面连边。然后题意可以转化成:给定一张有向图,可以调整每条边的方向,请问至少需要多少次才能让所有点都只有一个入度?

显然对每一个联通块考虑树形 dp。不过我们需要分类讨论一下每一个联通块的情况:

  • 当联通块是一棵树时:

    显然最后形成的图一定是已某个点为根,所有的边全部指向儿子。那么就设 \(f(i)\) 表示根节点为 \(i\) 时的答案,直接换根 dp 即可。

  • 当联通块是一颗基环树时:

    与上面类似,我们采用传统的处理方式,将基环树上一条边断开,然后做 dp。最后统计这两个点上的信息即可。

  • 否则:该联通块不可能满足要求,即直接得到无解。

T4

20 pts\(O(2^{2^{n-1}})\) 枚举叶子节点状态,此时每个贵族选什么最大是一定的,统计即可。

100 pts

应该想到,既然已知叶子可以得到父亲状态,那么知道父亲状态也能得到叶子状态,而且枚举一个节点的父亲只是 \(O(2^{n-1})\) 的。

那么我们就考虑枚举当前这一个点上的状态,然后向下递推。接下来去回收此时儿子做出的贡献,这里就需要用树形 dp 了。设 \(dp(i,j)\) 表示当前状态下,点 \(i\) 所管辖的叶子中,有 \(j\) 个选择打仗的最大贡献。那么枚举左右儿子的贡献,转移方程就是:

\[dp(p,i+j)=\max\{dp(lp,i)+dp(rp,j)\} \]

我们每一次枚举当前节点的状态,然后向下递归并转移,类似于树上背包。每一次合并的复杂度是 \(O(m^2)\) 的。此时复杂度略有些炸。实际上,我们对于第 \(i\) 层的节点,枚举的 \(i+j\) 实际上最多是 \(2^{n-dep}\),我们只需要枚举到这个值即可,复杂度大概是 \(O(4^n)\) 级别,可以通过。

39 CSP-S 模拟赛21

1 得分

题目 T1 T2 T3 T4 总分
得分 \(40\) \(50\) \(40\) \(30\) \(160\)

排名:rank \(2\)

2 题解

T1

最后形成的图形只有两种可能。一种是水晶球形成上下两个梯形,一种是空白形成上下两个梯形。如下图:

0111111110000000
0111111100000000
0111100000000000
0000000001111110
0000000011111111

表示水晶球成两个梯形的情况。那么我们枚举中间的分界线,以及两个峰顶所在的坐标,利用组合数公式计算即可。这样复杂度是 \(O(n^3)\) 的,利用后缀和优化可以做到 \(O(n^2)\)

这里需要用到一个公式:对于长度为 \(x\),首项 \(\le y\) 的单调不升序列的个数是 \(C_{x+y}^x\)。利用这个公式就可以快速求出梯形峰顶两端排布的方案了。注意去重。

T2

首先显然需要删边改加边,然后考虑加边怎么做。考虑到树上距离一个点最远的点一定是直径一端点,因此维护出连通块直径即可。维护直接上并查集,利用经典定理(两点集并的直径端点集合一定属于两点集直径端点集合的并)做即可。

T3

看到矩形,想到扫描线。我们可以利用扫描线去维护出每一个矩形的修改,然后对每一行求解答案即可。但是发现线段树上不好维护小于 \(k\) 的数的大小,考虑到 \(k\le 10\) 非常小,可以在线段树的区间上维护出前 \(k\) 小的值,这样 \(<k\) 的值一定在其中。合并时直接归并排序,复杂度 \(O(nk\log n)\)

做完线段树后考虑求解。设每一行上 \(<k\) 的有 \(a_i\) 个,再设 \(b_i=\min\{a_i,m-a_i\}\)。显然该行选出 \(y\) 个的方案数就是 \(\min\{b_i, \lfloor\dfrac y 2\rfloor\}(y-\min\{b_i,\lfloor\dfrac y 2\rfloor\})\)。分类讨论 \(b_i\)\(\lfloor\dfrac y 2\rfloor\) 的大小然后利用前缀和计算即可。

T4

考虑这样一件事,如果单独只有加操作或单独只有删操作,dp 数组是容易去重新计算的。但是现在操作实际上是同时有加操作和删操作的,因此 dp 数组就无法很好的维护。我们考虑这样一种思路:维护两个栈,两个栈栈底相接,上面一个栈开口朝上,栈底为 \(m\);下面一个栈开口朝下,栈底为 \(m+1\)。这样我们删除的时候只需要在上面的栈弹出并更新 dp 数组,加入的时候压入下面的栈并更新 dp 数组即可。

那么思路就是这样,接下来是具体的实现。发现如果将信息拆成两个栈,我们就必须借助 \(m\) 为跳板来走。考虑到从第一行 \(head\) 走到最后一行 \(tail\) 的方案实际上有两种:

  • \(head\to m\to tail\)
  • \(head\to m-1\to m+1\to tail\)

因此我们考虑维护两个 dp 数组。设 \(f(i,j,k)\) 表示从坐标 \((i,j)\) 到坐标 \((m,k)\) 的路径条数(或 \((m,k)\)\((i,j)\)),\(g(i,j,k)\) 表示从坐标 \((i,j)\) 到坐标 \((m-1,k)\) (或 \((m+1,k)\)\((i,j)\))的路径条数。那么我们就可以在操作的时候维护出两个数组并计算方案数了。

考虑当上面的栈删完的时候怎么办,很简单,将下面的栈中所有元素弹出并压到上面的栈中,相当于对两个栈进行重构。这样可以保证每一行只被重构一次,复杂度 \(O(nq)\)

40 CSP-S 模拟赛22

1 得分

题目 T1 T2 T3 T4 总分
得分 \(40\) \(35\) \(60\) \(0\) \(130\)

排名:rank \(17\)

2 题解

T1

考虑到一个雪球跨过另一个雪球原位置后就不会在产生任何贡献了,因此该雪球能够接受的贡献实际上就是它与相邻雪球的区间的连续一段。也就是说我们只需要考虑一个区间对两端的贡献是怎样分割的。我们可以考虑求出每一时刻两端点的扩展长度,当两者第一次重合时就可以计算答案了。显然这具有单调性,使用二分即可。

T2

假设总共有 \(cnt\) 只七彩蝶,同时最后我们将矩形分成了 \(x\times y\) 块,那么一定有 \(2xy=cnt\),即 \(xy=\dfrac {cnt}2\)。考虑枚举 \(x\),这样就能快速求出 \(y\)。接下来考虑怎样求出答案。

我们先对横切和纵切分开考虑。若当前行的下一个空隙是第 \(k\) 次横切的话,一定会满足该行及之前的七彩蝶数量等于 \(2ky\)。我们就可以利用这条性质去求处每一次横切有几种可能;对于纵切同理。最后将每一次切的可能相乘即可得到答案。

但是我们并不能保证行列结合起来是有答案的,因此还需要用任意一种方案检验一下,检验可行再累加。

T3

首先暴力 \(O(n^3)\) dp 是显然的,但是在看到题目中要求的是 “魔力值的最大值最小” 后,也应该想到二分答案。

那么考虑将这两者结合起来,此时的 dp 就成了判定性的 dp,设 \(dp(l,r)\) 表示区间 \([l,r]\) 能否在 \(x\) 的魔力值之内消完,那么这个就可以使用 bitset 优化了。复杂度看似是 \(O(\dfrac{n^3\log n}w)\) 的,但是实际上可以对 dp 过程进行优化,避免大量不必要的状态,这样时间是可以卡过的。

还有一种方法,我们可以不二分,单次扩大限制 \(x\)。那么显然,此时直接影响到的 \(dp\) 值就是满足 \(cost(l,r)=x\)\(dp(l,r)\),而它还会间接影响其他 dp 值。考虑每一次进行一个 BFS,将会被影响的 \((l,r)\) 压入队列并扩展,这样复杂度是 \(O(\dfrac{n^3}w)\)

T4

这个题用的科技有点小多。

首先我们考虑单点修改怎么做,显然带修莫队是可行的,但是带修莫队无法扩展到区间修改,因此我们需要放弃。考虑这一类题的另一个经典做法,我们对于每一个位置,求出一个 \(pre_i\),表示 \(i\) 之前第一个和 \(i\) 同色的位置(若是第一次出现该颜色则 \(pre_i=0\))。那么当我们查询一个区间 \([l,r]\) 的信息的时候,实际上就是查询所有 \(i\in [l,r],pre_i\in[0,l-1]\)\(i\) 的位置。

接下来考虑单点修改,显然操作会导致的修改只有 \(i\) 以及 \(i\) 后面第一个与 \(i\) 同色的点的 \(pre\) 值。我们简单维护一下即可。加上上面的查询操作,这就是一个二维平面上的修改和数点问题。显然二维树状数组或二维线段树都不可做或难做,我们不妨考虑 CDQ 分治。接下来就会发现,这就是 CDQ 分治的一大经典应用 “动态变静态”,此时再利用树状数组辅助求解即可。

那么现在考虑改成区间覆盖,此时 CDQ 分治的过程是不需要改的,只需要更改修改 \(pre\) 的过程。考虑到区间覆盖的时候 \(pre\) 值改变的点,只有区间内所有颜色相同连续段的左端点,以及该区间内出现的颜色在区间右边的第一个点。此时考虑到修改就是区间覆盖颜色,同时我们还要维护区间内颜色相同的连续段,可以想到利用珂朵莉树进行求解。具体的,对整个区间开一颗珂朵莉树,再对每一种颜色开一颗珂朵莉树,记录下 \(pre\) 的修改然后 CDQ 求解即可。

posted @ 2024-08-08 21:41  UKE_Automation  阅读(70)  评论(0)    收藏  举报