JOISC 2015 简要题解

「JOISC 2015 Day1」复制粘贴 2

  • 给定初始字符串,\(n\) 次操作形如 \((a,b,c)\),表示把 \((a,b]\) 复制并在 \(c\) 后粘贴。
  • 每次操作后检查,若序列长度超过 \(m\),只保留 \([1,m]\)。求最终序列的 \([1,k]\)
  • \(k\leq 200,m\leq 10^9,k\leq |s|\leq \min(m,2\times 10^5),n\leq 2\times 10^5\)

观察到 \(k\) 很小,发现 \(O(nk)\) 的算法是可以接受的。

考虑对每个位置倒序找到最初始的位置即可,倒序的过程很容易。

「JOISC 2015 Day1」愉快的标志设计

  • 定义 \(0\) 级串为 J/O/I 三选一。
  • 定义 \(k\) 级串可以由 \(4^{k-1}\)J\(4^{k-1}\)O\(4^{k-1}\)I,以及一个 \(k-1\) 级串按顺序拼接得到。
  • 容发现 \(k\) 级串的长度为 \(4^k\)
  • 现给定一个长度为 \(4^k\) 的序列,求至少要修改多少位,使得该序列的某个循环同构串为 \(k\) 级串。
  • \(k\leq 10\)

枚举 \(0\) 级串的初始位置,那一位显然不用动。

之后每个位置的字符就都确定下来了,直接 \(O(k)\) 的计算就好。

「JOISC 2015 Day1」有趣的家庭菜园 2

  • 给定每个位置 \(3\) 个参数 \(h_i,p_i,c_i\)。分别表示该植物的高度,若它能结果赚得的收益,以及移除它的代价。
  • 一个位置的植物能结果,当且仅当对于它左右至少一边,存留的植物的高度都 $\leq $ 它。最大化利益。
  • \(n\leq 10^5\)

发现保留的一定是单峰的,所以一定存在一个峰值,它左边的数都通过左侧 \(\leq\) 它来合法,右侧同理。

那就直接左右各扫一遍然后枚举中间位置,扫的过程直接用线段树维护即可,下标表示当前以某个高度结尾的最大利益。

「JOISC 2015 Day 1」卡片占卜

  • 给定 10101 分别有连续 \(A,B,C,D,E\) 个的序列,以及 \(n\) 个区间翻转操作。
  • 每个操作的代价为区间长度,求使得序列全 1 的最小代价。
  • \(A+B+C+D+E,n\leq 10^5\)

用图论建模巧妙的解决一些最优化问题,甚至可以构造性的给出解。

对于能够翻转的区间 \([l,r]\),考虑连双向边 \((l,r+1)\)。这样对于任意 \(s,t,s<t\),一定有仅翻转区间 \([s,t)\) 的最小代价就是 \(\text{dis}(s,t)\)

现在是要翻转两个独立的区间,经过讨论发现方式只有常数种,跑常数次最短路即可。

「JOISC 2015 Day2」Building 3

  • 给定长度为 \(n-1\) 的序列 \(B\),求满足条件的 \(A\) 的个数。
  • 使得其长度为 \(n\),去掉一个位置后等于 \(B\),且存在排列 \(H\) 使得对每个 \(i\),以 \(H_i\) 为结尾的最长上升子序列长度 \(=A_i\)
  • \(n\leq 10^6\)

满足条件的 \(A\) 的充要是:前缀\(\max\)逐次递增 \(1\)。构造充分性和必要性都比较显然。

然后对着前缀 \(\max\) 统计一下,记得不重就好。

「JOISC 2015 Day2」Keys

  • \(n\) 个人的公司,出勤时间是 \(0\)\(m\),保证时刻 \(0\)\(m\) 时所有人都在公司内。
  • 每个人会恰好离开公司一次,在 \(s_i\) 时刻离开,\(t_i\) 时刻回到公司,所有 \(s,t\) 两两不同。
  • 初始 \(0\) 时刻,公司的大门是关闭的。大门从内部可以任意开闭,但从外部只有有钥匙的人可以打开或关闭它。
  • \(i\) 能在 \(t_i\) 时刻回到公司,当且仅当他有钥匙,或者 \(t_i\) 时刻门是打开的。
  • 你有 \(k\) 把钥匙可以任意分配给员工,并让他们以任意策略开关门。在所有人都能按时回到公司的前提下,最大化关门时间。
  • \(k<n\leq 2000,m\leq 10^9\)

将所有时间排序后,发现两个时刻之间的一段只和这两个人的决策有关,这一观察很重要。

考虑讨论四种情况对应的代价,\(i,j\) 是排序后相邻两项对应的两人:

  • \((t_i,s_j)\):无论怎样都有贡献。
  • \((s_i,s_j)\)\(i\) 有钥匙才有贡献,放到点 \(i\) 上表达。
  • \((t_i,t_j)\)\(j\) 有钥匙才有贡献,放到点 \(j\) 上表达。
  • \((s_i,t_j)\):两人都有钥匙才有贡献,建图连边 \((i,j)\) 表达

然后因为此图不可能连出环,所以把所有链串起来随便跑序列 DP 即可。这种把代价表达到边上的思想还是很厉害的。

「JOISC 2015 Day2」Road Development

树剖板子。

「JOISC 2015 Day 3」AAQQZ

  • 给定字符串,可以选择一个区间并将字符按字典序排序,最大化最终的最长回文子串。
  • \(n\leq 3000\)

考虑枚举排序的区间,按照排序后中点是否在排序区间中讨论。

如果在,一定是最小值的中点或者最大值的中点,直接 Hash 判断即可。

如果不在,枚举区间中点,尝试极大扩展,之后对着更长的区间,一侧是单调的一侧是要排序的,同样用 Hash 判断字符集是否相同。

Hash 方式:找一个 \(a\),来了一个字符 \(c\),就加上 \(a^{\text{rank}(c)}\),其中 \(\text{rank}(c)\) 表示字符 \(c\) 的排名。

现在问题变成询问 \(O(n^2)\) 次某两个子串,其中一个有序,求它们最长的字符集相等的前缀(或者)。

发现对于两个子串 \([a,b]\)\([c,d]\),无非是选择两个长度相等的前缀,根据之前的 Hash 方法,直接做差就能得到前缀 Hash 值。

前缀长度相等也就是 \([a,x],[c,y]\)\(x-a=y-c\),也就是 \(x-y=a-c\)。对定差的 Hash 函数 \(O(n^2)\) 预处理即可。

因为可能还有求什么等长前缀后缀匹配(定和预处理),写起来可能还是有点难度(口胡 ing)。

「JOISC 2015 Day 3」Card Game Is Great Fun

  • 每张牌有 点数、花色、权值,每次取出的牌除第一张外必须和上一次取出的 花色或点数 一样。
  • 每次能取出牌堆从上往下的第 \(1\) 或第 \(3\) 张牌,求取出牌的最大权值和。
  • \(n\leq 500\)

不难想到 \(f(i,j,k,l)\) 表示当前第 \(1,2,3\) 张牌分别是 \(i,j,k\),上一次取的是 \(l\) 的最大值。

发现是 \(O(n^4)\) 的,时空都不能接受。但是不难发现:

  • 如果上一次取的是 \(1\),那么有 \(k=j+1\)
  • 如果上一次取的是 \(3\),那么有 \(l=k-1\)

分别设为 \(f,g\),就均可 \(O(n^3)\) 的得到答案。

「JOISC 2015 Day 4」Inheritance

  • 给定无向图,保证边权各不相同。
  • 进行 \(k\) 轮,每次删去图中的最大生成森林,求每条边在哪一轮中被删除。
  • \(n\leq 1000,m\leq 3\times 10^5,k\leq 10^4\)

考虑每条边只会被删一次。

观察每次求最大生成森林的过程,无非是将剩余的边从大到小排序然后贪心的选取。

那么直接对边整体排序,然后显式的维护 \(k\) 个森林,每次二分的找到第一个能容下当前边的森林即可。

「JOISC 2015 Day 4」Limited Memory

  • \(22\) 位 bit 来压缩之前所有询问的信息,每次询问可以查询括号串的一个位置。
  • \(15000\) 次询问内判断该长度 \(\leq 100\) 的括号串是否合法。

询问次数 \(>n^2\),可以枚举每个位置,然后找匹配。

中间是否匹配不管,只进行左括号 \(+1\) 右括号 \(-1\) 而不过类型,到第一次栈为空的时候看能否匹配自己即可,这么问 \(O(n^2)\) 次显然已经充要了。

压缩需要 \(1+6+7+7=21\) 位,分别表示 括号类型、栈大小、当前位置、需要匹配的位置。

栈大小显然如果 \(>50\) 就一定不合法了,所以只需要 \(6\) 位,还有一位可以拿去当零食。

「JOISC 2015 Day 4」防壁

  • 给定 \(n\) 个区间,有 \(m\) 次操作,每次要求所有区间在 \(p_i\) 处重合。
  • 对每个区间求出它的最小移动距离。
  • \(n,m\leq 2\times 10^5,l_i,r_i,p_i\leq 10^9\)

神题……

首先考虑贪心,每个区间要么不用移动,要么移动到恰好某个边界为 \(p_i\) 为止。

下面只需要快速模拟这个过程……

看到 \(A_i=0\) 的部分分,大概率和正解直接相关,所以直接从这里入手。

将所有区间按照 \(B_i\) 升序排序,对于每个 \(p_i\),如果它能让第 \(i\) 个区间有移动,那么 \(i-1\) 也一定会移动。

这说明每个询问能造成影响的区间是有单调性的,或者说,一段前缀。原因很直接,长的区间一定比短的区间优。

这样,如果处理出对每个区间有影响的序列 \(p_1,p_2,\cdots ,p_k\),那么就可以计算它的答案。

方法:

  • 先假设全都有贡献,答案为 \(\sum |p_i-p_{i-1}|\)
  • 考虑 \(\operatorname{dir}_i\) 表示第 \(i\) 次询问和上一次的相对关系,即 \(\operatorname{dir}_i=[p_i>p_{i-1}]\)
  • 如果 \(\operatorname{dir}_i\neq \operatorname{dir}_{i-1}\),称之为出现拐点。
  • 如果有拐点,那么答案会减少对应的 \(\text{len}=B_i-A_i\)
  • \(\text{ans}=\sum |p_i-p_{i-1}|-\text{len}\times c\)\(c\) 为拐点个数。

结合上面的单调性,在得到每个 \(p_i\) 影响的前缀后,扫描线扫一遍,不难用链表维护删数过程,求出每个区间的答案。

问题在于求出每个 \(p_i\) 能影响的前缀,考虑整体二分,发现每个 归入左边的数 会被其前面的 归入右边的数 影响。

解决方法很简单,直接用数组记录最近一次的影响,结合当前上一次的影响得到真正的最近的影响。

然后根据影响的 \(\text{dir}\) 得到当前线段的真正位置,从而贪心的得到当前点是否对当前二分的前缀有影响。

以上是 \(A_i=0\) 的部分分。

后面比较简单,直接大胆考虑 \([a_i,b_i]\)\([0,b_i-a_i]\)\(\Delta\)

发现,可以尝试找到第一个前缀极差 \(>b_i-a_i\)\(p_k\)

  • 在这之前,两个线段都是单向移动,可以简单计算。
  • 在这之后,两者位置重合,就是之前计算的答案。

若没有这样的极差,说明该线段一直单向移动,直接简单计算即可。于是做完了。

posted @ 2022-10-25 20:37  LPF'sBlog  阅读(347)  评论(0编辑  收藏  举报