【题解】蓝桥算法双周赛 第一场

D. 健身

题意:在未来 \(1\sim n\) 天中可以安排健身计划。有 \(m\) 个健身计划,第 \(i\) 个计划需要连续的 \(2^{k_i}\) 天,增益为 \(s_i\)。一个计划可以多次完成并获得多次增益,但一天不能同时进行多个计划。在 \(1\sim n\) 天中有 \(q\) 天有其它安排,不能健身。问能获得的最大增益。

\(1\le q\le n \le 2\times 10^5\)\(1\le m \le 50\)\(1\le s_i \le 10^9\)\(0\le k \le 20\)

对于相同的 \(k\),显然只需要保留增益最大的 \(s_i\)

\(w_k\) 表示锻炼 \(2^k\) 天能得到的最大增益值。

\(dp_i\) 表示锻炼到 \(i\) 天可以得到的最大增益,那么: \[dp_i=\max(dp_{i-1},dp_{i-2^k}+w_k)\] 转移的前提是第 \(i-2^k+1\) 天到第 \(i\) 天必须空闲。

判断一段时间是否空闲可以用前缀和 \(O(1)\) 判断。

时间复杂度 \(O(nk)\)

E. 契合匹配

题意:用一个首尾相接的由英文字母组成的字符串表示一个齿轮。两个齿轮是契合的当且仅当每个对应位是同一个字母的大小写,如 AbCDeFghaBcdEfGH 。齿轮是环形的,问第一个齿轮 \(S\) 至少旋转多少位能与第二个齿轮 \(T\) 完全契合,或无论如何都不能契合。

\(1\le |S|,|T|\le 10^6\)

套路:破环成链。

以题例为例,\(S=\text{AbCDeFgh}\),延长一倍后变成 \(S=\text{AbCDeFghAbCDeFgh}\)

另外,可以将 \(S\) 大小写反转,变成纯粹的字符串匹配问题,如反转后:

\(S=\text{aBcdEfGHaBcdEfGH}\)\(T=\text{aBcdEfGH}\)

那么假设 \(T\)\(S\) 中出现的首位为 \(p\),则 \(ans=\min(p-1,n-p+1)\)

利用 KMP 算法匹配字符串,时间复杂度 \(O(n)\)

F. 奇怪的线段

题意:数轴上给定 \(n\) 个线段 \([l_i,r_i]\)\(q\) 次询问两个点 \(a,b\) 问有多少个线段包含 \(a\) 而不含 \(b\)

\(1\le n,q,a_i,b_i \le 2 \times 10^5\)\(1\le l_i < r_i \le 2\times 10^5\)

先考虑只有条件 “ 有多少个线段包含 \(a\) ” 怎么做。

用一个 vector 存以 \(i\) 为左端点的线段的右端点是哪些。

从左到右扫,每遇到一个左端点就把右端点插进线段树(单点加一),每遇到一个右端点就把该点从线段树中删掉(单点减一),遇到 \(a\) 时查询线段树中的节点数量(区间求和)就是答案。

ps. 数轴上的一个点可能是多个线段的左/右端点,所以实际上我们是减去对应 vector 的大小。

但现在是 " 包含 \(a\) 而不包含 \(b\) " 。

改进方法是:查询局部区间和而不是全局区间和。

具体的:

  1. 如果 \(a=b\),答案为 \(0\)
  2. 如果 \(a<b\),从左到右扫描,遇到左端点把右端点插进线段树;遇到右端点则将右端点从线段树中移除,扫描到 \(a\) 时,查询 \([a,b)\) 区间和即为答案。
  3. 如果 \(a>b\),从右到左扫描,遇到右端点把左端点插进线段树;遇到左端点则将左端点从线段树中移除,扫描到 \(a\) 时,查询 \((b,a]\) 区间和即为答案。

预处理出 \(2,3\) 两种情况对应的询问,扫两次即可。

时间复杂度 \(O((n+q)\log n)\)


【题解】蓝桥算法双周赛 第一场
https://kisuraop.github.io/posts/55f142fc.html
作者
KisuraOP
发布于
2023年10月20日
许可协议