被 JOISC 板刷
被 JOISC 板刷
[JOISC 2023 D1] Two Currencies
我们先考虑固定 \(s,t\) 怎么做。你发现金币的作用相当于是让我们跳过一条边不用付钱。那我们把这路径上的所有边按银币数排序,我们肯定用银币付能付的一个前缀,然后后面的就只能用金币来付了。
那我们考虑上树。进行一个树剖,然后相当于在这 \(\log\) 个链上找最多的能用银币付的边。我们采纳序列问题的做法,进行二分,问题转化成询问一条重链的一个部分,小于等于一个值的和是多少。这个可以使用主席树实现。
清算复杂度,二分、树剖、线段树分别带来一个 log,总复杂度 3 log。
注意到我们给的是一个在线做法,考虑离线以降低复杂度。
整体二分,每次从前到后扫一遍,一共扫 \(\log\) 变。每次扫到一个点的时候要做一个线段树上单点修改,这是 2 log。询问要询问 log 个链上的和,这又是 2 log。总复杂度 2 log。
*?! [JOISC 2023 D1] Festivals in JOI Kingdom 2
我们看一眼,确定 \(a\) 之后,\(b\) 的选择不是唯一的。emm,这不太好。
我们先考虑最后怎样的区间贪心无法得到最优解。
这个时候你发现这个序列 \(a,b\) 都是假的,其实就是问你有多少种构造区间的方案数。
我们发现这个问题我们有一个正确的贪心做法,就是按照右端点排序,然后从小到大依次取。这里相当于是按照左端点进行了排序。
你发现如果我们把有包含关系的区间删掉之后,两种贪心的解是一致的。所以可能出问题的地方就在有包含关系的区间。
进一步,我们发现一个区间在假贪心中被选择,当且仅当没有区间跨过左端点。一个区间在真贪心中被选择,当且仅当没有在它前面、与它相交但不包含的区间。
现在可以状压做一个比较神秘的复杂度,大概能过到 \(8\)。
现在的问题是我们不知道怎样的方案满足假贪心是错的,具体一点,我们发现哪怕现在这个区间假贪心跟真贪心的选择方案不一样,它们最后仍然可能得到相同的解。
当然,我们也可以直接开始 dp。考虑目前已经有 \(p\) 个未匹配的左端点,我们希望维护当前的解。最暴力的想法就是多加两个维度来记录当前两个贪心解都是多少,当然为了维护真贪心我们还要再多记一维。现在复杂度是 \(O(n^5)\)。
如果我们增加了一个左端点,并且此时没有未匹配的左端点,我们假贪心的解就加 1。如果我们增加了一个右端点,并且这个右端点匹配的左端点在上一个右端点之前,我们真贪心的解就加 1。通过分析我们发现假贪心的解最多比真贪心大 1。猜测在这个过程当中两个贪心的解不会相差太多。
也就是说,相当于假贪心的两次 \(+1\) 之间,真贪心至少要 \(+1\)。所以好像假贪心的解要始终 \(\ge\) 真贪心,才可能有解。那我们记录解的过程可以改成记录一个 \(0/1\)。现在复杂度是 \(O(n^3)\)。
额,sol 里面说,对于在右端点前的插头,我们可以提前给它们分配右端点,乘一个组合数就可以了。怎么想到的???
? [JOISC 2023 D2] Council
你记 \(f_{st}\) 表示是否有 \(st\) 这个数。
经过分析,我们只关心那些还差 \(1,2\) 票就被否决的提案。当我们枚举 \(a_i\) 之后,相当于是我们接下来会只关心 \(b_i\) 里的位,相当于是要找一个 \(j\),求 \(\min_{j\neq i}(|b_i\&a_j|)\)。
你求出一个 \(g_{st}\),如果有 \(st\) 的位置全是 \(0\) 的,那么它的值是 \(|st|\),否则是 \(0\)。
我们原本要算 \(\forall i,\min_{j\neq i}(|b_i\&a_j|)\),\(|b_i\&a_j|=|b_i|-|a_j 在 b_i 中 0 的个数|\),也就是说我们要求 \(\max_{j\neq i}|a_j 在 b_i 中 0 的个数|\),事实上这是 \(\max_{st\subseteq b_i}g_{st}\)。
剩下一个问题是 \(j\neq i\),我们可以类似于求一个最小值一个次小值的做法来解决。
题解区的另一种做法也值得学习。
*! [JOISC 2023 D2] Mizuyokan 2
这个题的翻译特别逆天,最后看原文才读懂。
给你一个序列,有两种操作。
单点修改。
对子区间 \([l,r]\) 进行询问:你可以把一些相邻的数合并(变成它们的和),要求最后数的大小关系呈严格锯齿状,问最后最多能剩下多少项。
\(n\le 2.5\times 10^5,q\le 5\times 10^4,1\le a_i\le 10^9\)。
首先这个锯齿状我们可以分成先增后减和先减后增两种情况,区别并不大,我们下面只考虑先增后减的情况。
你发现这是一段大一段小,那因为 \(a_i\ge 1\),所以小的那段肯定只有一个数。那么一个区间合法等价于这个区间除了最后一个数以外的和,要大于最后一个数,要大于这个区间的上一个数。现在我们会单次 \(O(n^2)\)。
考虑优化,\(s_i-2a_i>s_{j-1},s_i-a_i>s_{j-1}+a_{j-1}\),这相当于是个在线的二维偏序,我们当然可以 \(O(n\log^2n)\) 解决。但是注意到 \(s_{j-1},s_i-a_i\) 都是递增的,所以我们可以简单做到 \(O(n\log n)\)。
但是这个其实没啥前途。
我们接下来先考虑 \(l=1\) 的特殊性质。这修改很麻烦啊,改了一车东西。
这东西是个图,是个最长路。
呃呃不会了。感觉这个修改很神秘啊。
看了 sol。
你发现一个长段是否合法只跟它本身相关。也就是说我们可以把所有合法的长段提取出来,现在相当于要求找一些不相交的最多长段。那这个做法肯定是贪心。
你考虑记 \(to_r\) 表示 \(r\) 的最近的一个合法 \(l\),你每次从前往后,能放就放就可以了。
类似地,如果有一个 \(l\) 的限制的话,我们同样可以做。
接下来这里很有意思。你发现如果一个 \([l,r]\) 不合法,说明 \(a_{l-1}\) 比它们的和都要大,所以你扩展到 \([l-1,r]\) 就会翻倍。这样,我们 \(r-to_r=O(\log V)\)。
所以,我们一次修改只会影响后面大概 \(O(\log V)\) 个点。我们暴力修改,然后查询可以用线段树稍微多维护 \(O(\log V)\) 个信息就可以了。
上面说的有问题,因为如果 \(a_{r+1}\) 是一个比较大的数,那 \(to_r\) 就寄了。
我们考虑一个 \(nxt_r\) 表示最小的 \(k\) 满足 \(to_k\ge r+2\),也就是下一个能拼上的右端点。你考虑从右侧任意一个位置开始拓展,往左往右最多都不超过 \(O(\log V)\) 次,所以 \(r-nxt_r=O(\log V)\),我们尝试维护 \(nxt_r\)。\(nxt_r\leftarrow nxt_{r+1}\),然后尝试找到一个 \(to_k=r+2\) 的 \(k\) 即可,这个是好做的。
我咋一个题都不会啊。
*! [JOISC 2022 D1] 京都观光
额首先我们来不务正业一会,研究一下这个限制“不会走远路”到底有没有用。
首先,如果起点和终点不一定是这个东西的两个顶点的话,那肯定寄了,因为比方说起点上面还有一行,这一行很便宜,起点可能会向上走。
但是我们的问题里这两个点一定是顶点,那是不是仍然正确呢?
我们考虑反证法,你取最后一次走回头路(向左或向上),比方说最后一次回头路是 \(P\to Q\) 向上走,那这样 \(Q\to T\) 就都是向右向下走的了。
你考虑 \(Q\) 这一行的权值是 \(a\),然后 \(P\) 这一行的权值是 \(b\),如果 \(a\ge b\),那么我们可以在右侧“裁弯取直”,如果 \(a\le b\),那么我们可以在左侧“裁弯取直”,一直进行下去,我们可以证明最优解一定不会绕远路。
这个我想得有点久了,感觉有一个角度是你发现你会的其实只有这个“裁弯取直”,然后你就对着凑一类的可能会更快?
然后回到这个题上头。
有一个观察是,你找到行最小值和列最小值,然后我们发现这个交点是一定要经过的,然后分治下去一类的。不过这东西我不好说能不能做。
呃呃看了 sol 好像比较神秘(日语看不懂啊)。
哦我看懂了。但是这东西是人能想出来的吗???
我们考虑一个 \(h,w=2\) 的情况。它们的权值、长度分别为 \(a_1,a_2,l_a,b_1,b_2,l_b\)。
那么两种行走方案的权值分别是 \(a_1l_b+b_2l_a,b_1l_a+a_2l_b\),你进行一个比大小,发现是 \(\frac{b_1-b_2}{l_b},\frac{a_1-a_2}{l_a}\)。
所以你比较一下斜率,谁的斜率小就说明它更好一点。
你可能会觉得这就是局部的情况,没啥用。我们放到 \(h,w\) 很大的时候考虑一个相邻的这么个结构。
你发现如果 \(b\) 斜率更大一点,那么我们一定不会先向下再向右,也就是说我们在这里不会拐弯。
进一步,如果我们找到全局斜率最大的位置,那你发现这一溜都不会拐弯,换句话说,相当于这一溜没有用,我们可以直接删掉。
那么我们维护这个过程,同时维护终点的变化,可以做到 1 log。
但是还有更厉害的做法。
我们观察刚刚的这个过程,你发现恰好是删到两个维度分别的凸包上的点的时候终点会发生变化。所以我们可以先求凸包,不在凸包上的点直接删掉。然后在凸包上我们想怎么做,你发现就是从起点开始,然后看谁斜率小就往哪边走。维护这个过程,可以做到线性。
[JOISC 2022 D1] 错误拼写
这个,显然,我们要先研究你怎么比较 \(T_i,T_j\) 的字典序。
不妨令 \(i<j\),你发现其实就是找 \(S[i,\dots,j]\),然后如果这一段全都相同,那字典序就相等。否则找到第一个前缀变化的位置,如果形如 aaab 就是 \(T_i\) 小,否则 \(T_j\) 小。
我们来分析一下限制,显然连成了一个有向图。缩点,对于在同一个 scc 当中的显然是一些区间覆盖,要求这个区间内必须都相同。
把相同的区间给缩起来。然后你发现就是有一些区间的限制一类的东西。
考虑 dp,你记 \(dp_{i,v}\) 表示目前考虑到 \(i\),\(s_i=v\)。我们一段一段转移,枚举上一段的终点 \(j\),额你发现不行。
你再多记一维,记一个上一段的终点是谁,这样我们就可以 \(O(n^3v^2)\) 转移。
转移我们不一段段进行,而是考虑下一个位置填什么,这样可以做到 \(O(n^2v^2)\),没准是 \(O(n^2v)\)。
你发现这个东西很蠢啊,你考虑钦定某些位置是间断点,然后你 dp 这个东西,大概感受一下应该可以优化到 \(O(nv)\)。
~ [JOISC 2022 D2] 复制粘贴 3
感受一下这个剪贴操作有啥用。你如果光剪切不粘贴那就是删除,这毫无卵用。如果你剪切之后粘贴那就是不能扣得相交的印章。并且你发现剪贴板里的东西一定是依次包含的。
那就很好办了,你设 \(dp_{l,r}\) 表示拼出 \(s[l\dots r]\) 最少代价,你考虑这次操作的印章是 \([l',r']\) 然后算一算。
你发现爆炸了,这东西起码是 \(O(n^4)\) 的。
冷静思考一下,我们发现,我们其实一次转移了很多步。考虑一次只转移一步。
如果 \([l,r]\) 的拼接方式当中,最靠边的部分不是扣印章的,那就可以从 \(dp_{l+1,r},dp_{l,r-1}\) 转移过来。
如果靠边的部分就是扣印章的,那你发现这印章一定是当前串的 border。
额那其实这个只是减少了一部分没有用的转移,现在我们同一种操作方式转移唯一了。这是 \(O(n^3)\) 的,很难再用这个方法继续优化了。
额看了 sol,你发现这做法其实就是对的。
具体来说,我们枚举 \([l,r]\) 作为印章,然后你发现会改变你的转移方式的位置只有 \(\frac{n}{r-l+1}\) 个,这样总共复杂度是 \(O(n^2\log n)\),你只需要预处理出来 \(to_{l,r}\) 表示在 \(r\) 右侧 \(S[l,r]\) 下一次出现的位置就可以了。
* [JOISC 2022 D3] 蚂蚁与方糖
你发现这是一个带动态加入的二分图最大匹配问题,当然这个二分图有一定特殊性:左部点向右部点连的是一个区间。
这特殊性带给我们一个非网络流的算法:对左部点从小到大贪心,每次匹配能匹配的点里头最小的一个右部点。现在我们会了单次 \(O(n)\)。
你考虑继续分析上面这个算法。
我们以方糖和蚂蚁间隔排列,\(l=1\) 的这个 sub 为例思考。你发现上面这个贪心麻烦在它会受到来自前面的东西的影响,而这影响是难以表达的。但其实经过观察,你发现,这影响可以用一个数来表示。具体而言,你可以记录下来之前的位置给它留下来的有多少个方糖/蚂蚁,然后我们可以把答案表示成关于这个的函数,之后只需要考虑这样的函数的合并就可以了。
记 \(f(x)\) 表示给了 \(x\) 个方糖的答案,\(g(x)\) 表示给了 \(x\) 个方糖,最后能剩下多少个方糖。经过一些简单的思考,我们发现 \(f(x)\) 先是一段 \(k=1\) 的线段,然后变平,\(g(x)\) 先平,然后 \(k=1\),然后再平。并且它们的变化点是相同的,这些函数容易用几个数来表示。
现在,我们只需要套一个线段树就可以做这个 sub 了。
但是这做法好像不是很有前途,因为 \(l\) 一旦大起来,前面对后面的影响仍然是难以描述的。
不对好像也可以描述,因为我们在前缀被取干净之前不会碰后面的,所以你可以记 \((i,v)\) 表示目前我们把 \(b_i\) 取得剩 \(v\) 了。不过这个东西就真的比较复杂了。
额瞄了一小眼 sol,说 Hall 定理启动!很对啊!
我们转成点覆盖,再转成 \(n-独立集\)。
然后你发现其实就是你选一段左选一段右这样交替来,不过要求相邻的两个之间至少要间隔 \(L\)。
这个至少要间隔 \(L\) 太麻烦了,我们考虑进行一些转化。
比方说我们认为我们自己来选左部点,然后右部点自动选择剩下的部分。这样,如果我们分别记左右部点的前缀和是 \(R,B\) 的话,一个 \([l,r]\) 的左部点区间贡献就是 \((R_r-R_{l-1})-(B_{r+L}-B_{l-L-1})\),拆一下,\((R_r-B_{r+L})+(-R_{l-1}+B_{l-L-1})\),这跟两个端点是独立的,所以我们可以分别记成 \(r_i,b_i\)。
然后你发现,即使 \(r,b\) 选取方式不是间隔至少 \(L\) 也无所谓,所以我们接下来就是要求,\(r,b\) 交替选择。
然后你考虑修改操作,如果左部点 \(x\) 加了 \(v\),那就是 \(i\ge x,r_i\leftarrow r_i+v\),并且 \(i>x,b_i\leftarrow b_i-v\),但是你发现如果对一个区间进行一个 \(r+v,b-v\) 操作,那其实这个区间的决策不会改变,答案的变化只跟它两端点选的是什么情况有关。所以这个操作事实上是一个单点修改 + 区间打 tag。
如果右部点 \(x\) 加了 \(v\),那就是 \(i\ge x-L,r_i\leftarrow r_i-v\),并且 \(i>x+L,b_i\leftarrow b_i+v\),仍然是一些区间打 tag,但是剩下的部分变成了一个区间 \([x-L,x+L]\) 加。
但是你发现这个区间长度是 \(2L+1\),而两个相邻的 \(r\) 之间距离至少要是反正是一个挺长的距离,所以这个区间的最优决策最多只会选择一个 \(r\)。而我们事实上知道这个区间里头到底有什么,所以直接做就可以了吧。
实现就用线段树维护 \(f_{0/1,0/1}\) 合并即可。
[JOISC 2022 D4] 一流团子师傅
一次 query(S) 操作的返回值,如果我们记 \(S\) 集合当中含有颜色 \(i\) 的数量为 \(s_i\),那就是 \(\min_i(s_i)\)。
那么我们有一个非常 naive 的想法:如果我们现在手头有一个恰好是一流团子的集合 \(S\),那我们对其中的每个元素,分别把它去掉,然后用这个集合依次加上每个元素,这样就能确定每个元素的颜色是什么。这复杂度起码是 \(O(n^2m)\) 的。
这做法似乎不是很有前途。我们考虑一些常规套路,比方说分治什么的。
如果 \(|S|=km\) 并且 query(S) 返回值为 \(k\),那我们就可以把 \(S\) 独立出去。
这有个好方法:如果你现在手头只有一个范围值为 \(k\) 的 \(S\),我们可以依次考虑去掉每个元素,只要返回值仍然为 \(k\) 就不管它,否则就把它加回来。
这样,我们一定可以在 \(O(nm)\) 的时间内,构造出任意 \(k\) 的 \(S\)。
分析时间复杂度 \(T(nm)=2T(n\frac m2)+O(nm)\),我们可以得到 \(T(nm)=nm\log m\)。而 \(\log m\approx 5\),但因为我们操作过程中有一个 \(2\) 的常数,所以可能要带一个 \(\frac12\) 的常数。
额你发现这个做法好蠢。因为整个集合一定是满足条件的,所以我们可以以它为初始做就可以了。
为了避免被构造卡,我们可以先 shuffle。当然这个做法没必要。
? [JOISC 2022 D4] 鱼 2
我们显然要分析一下某个鱼能 win 到最后的等价条件。
或者考虑反面,什么时候一个鱼 win 不到最后。你发现如果有一个区间 \([l,r]\) 满足 \(sum([l,r])<a_{l-1}\land sum([l,r])<a_{r+1}\),你发现 \([l,r]\) 内的鱼最多只能拓展到 \([l,r]\) 这个区间,那就输麻了对吧。
事实上这个条件显然是等价的。我们接下来专注于研究这样的合法区间 \([l,r]\)。
显然的性质是合法区间不能有那种不是包含的相交关系,也就是说,合法区间构成了一个树形结构。
另一个显然的性质是,这个树高是 \(O(\log V)\) 的,因为你拓展一次,sum 翻倍。
考虑我们怎么统计答案,你把贡献差分一下挂到树上的结点上,然后一次询问,就是找这个完全被这个区间包含的结点的贡献之和,这个是不难做的。
问题转化成怎么做修改,直观感受好像一次修改影响比较大。
但事实上,你发现修改一次影响的点大概是 \(O(\log V)\) 个,你就考虑从下面往上走,先把会影响到的点都给删了,这些点其实就是包含 \(x\) 的,\(r=x-1\) 的,\(l=x+1\) 的,这样的区间,显然分别都是 \(O(\log V)\) 的。
然后你考虑重建会被 \(x\) 影响的这部分区间。首先 \(r=x-1,l=x+1\) 这样的区间重建时非常简单的,包含 \(x\) 的区间,你可以考虑用 \(l=x,r=x\) 这类的区间拼起来试一试。
这样我们一次操作会修改 \(O(\log V)\) 个区间,我们直接树套树是 \(O((n+q)\log V\log^2n)\) 的,简直菜到不如暴力。
考虑有没有可能离线下来降低复杂度。历史上一共会出现 \(O((n+q)\log V)\) 个区间,我们相当于要处理 \(O((n+q)\log V)\) 次修改某一个区间的权值,以及 \(O(q)\) 次对 \([l,r]\) 进行查询。
考虑枚举 \(r\), 别考虑了。
我们注意到,我们的结构是一棵树,这就是说,如果我们对 \([l,r]\) 进行查询的话,事实上我们查到的应该是 \(lca(l,r)\) 的一部分连续的孩子的和。
所以,如果你使用平衡树维护每个点的孩子的话,查 \(lca\) 可以暴力跳,查询部分的复杂度可以做到 \(O(q\log n)\)。
修改部分,每次修改牵扯到 \(O(\log V)\) 个区间,我们需要重构树结构,你大不了枚举任意两个区间,复杂度也就是 \(O(n\log^2V)\)。
这样我们似乎就做到了奇怪的复杂度。
上面这个不太对,具体来说你可以看一眼 sol 里 zltqwq 的做法,跟我说的这个东西是差不多但是有区别的,他那个是正确的。不过本质上没啥不同。
学习了 Alex 的做法。
我们考虑反面,你对一个鱼 \(i\) 维护区间 \([l,r]\) 表示 \(i\) 可以吃了 \([l,r]\) 中所有鱼,但是无法继续扩张。
你考虑 \([l,r]\) 内的胜者长什么样子。你发现它一定能扩展到 \(l\),也能扩展到 \(r\),也就是说,存在一个它的区间 \([L,R]\) 包含住了 \([l,r]\)。
你考虑到同时包含 \(l,r\) 的区间不是很多,也就 \(O(\log V)\) 个。我们对每个这样的区间统计恰好能到这个区间的鱼的个数。
额算了这做法比我说的还要麻烦。
这个东西好像比较神秘,我仍然不是完全清楚所有细节,所以可能要再看看。
* [JOISC 2022 D4] 复兴计划
不是这题勰码讲过啊!!!为啥我还是不会!!!
我的一个思路,是你考虑对于一个 \(x\),对有些边它的系数是 \(+1\),有的是 \(-1\),我们肯定喜欢 \(-1\),所以你就找一个类似于凸包的东西。
这玩意没一点救的,找这凸包完全不会啊。
然后是 sol。
你发现一条边 \(e=(u,v)\) 想要成为生成树当中的点,当且仅当,所有边权比它小的边,都不能将 \((u,v)\) 连通。而所有比它小的边其实是 \([2x-W_e,W_e),x\le W_e\),或者 \((W_e,2x-W_e],x>W_e\)。
发现这都是按 \(w\) 排序后的区间,我们相当于要找最大的 \(p\),满足 \(p,p+1,\dots,e-1\) 已经可以把 \(u,v\) 连通了,以及镜像问题。
这个你显然不能 \(O(m^2)\) 找。但如果你从大到小枚举每一条边,然后尝试把它加到最小生成树当中,你会发现如果当前边 \(e'\) 把 \(e\) 干掉了,那就说明 \(e'\) 就是 \(e\) 要找的 \(p\)。
因为 \(n\) 很小,所以找 MST 可以暴力 \(O(nm)\)。
找完之后你就知道了每个边在 MST 当中的区间,随便做做就可以了。
\(O(nm+(q+m)\log n)\)。
这个感觉有点像,因为边权并不好处理,所以你先手动处理边权,然后做一些东西一类的。
* [JOISC 2022] 洒水器
额可能有显然的点分树一类的做法,但是这不是重点。
这个题 \(d\) 很小,所以我们在这上头下点功夫。因为不保证 \(l\) 是质数,所以没有逆元,我们必须保证所有操作正好覆盖所有点。
一个直观的冲动是我们枚举修改点的 \(d\) 个祖先,然后在祖先 \(\le x\) 位置打一些 tag。但是这个复杂度不好,并且会重复覆盖。
你考虑容斥,假设我们有逆元。首先肯定是修改的 \(u\) 会打 \(d\) 个 tag,然后考虑它的父亲,也该打 \(d\) 个 tag,但是这时你发现 \(u\) 会打一些逆元 tag,就把原来的 tag 消掉了,所以这部分 tag 根本没必要打。这样我们可以拆分成 \(O(d)\) 个不重不漏的 tag,就做完了。
[JOISC 2021 D1] 饮食区
这不是我们 pkuwc 的题吗???
你首先离线下来,然后转化成扫商店这一维,用数据结构维护时间这一维,变成了在时间轴上会激活/取消一些操作,然后会在某个时间位置询问第 \(x\) 个位置的是谁。
首先我们使用线段树来维护,就可以维护查询当前时刻的序列长度。那我们会判无解了。
然后问题就是怎么查询这个位置到底是谁。因为我们不大可能真的开一个数据结构给它把这个序列记录下来,所以我们另一个考虑方式就是把位置定位到修改上,也就是说,我们查询出这个位置是哪次修改最后一次覆盖的。
你比方说在 \(p\) 时刻的一次添加操作,如果操作结束之后,序列长度 \(s\ge x\) 并且在这之后的所有操作减法减到的最小位置也 \(\ge x\),那就说明就是这里了。并且这整个条件是可以二分的。
具体来说,你二分的条件是:仅考虑 \([1,i]\) 操作时,\([mid,i]\) 这些位置操作结束时的值的最小值是否都 \(\ge s\)。
这个可以通过先计算 \(mid\) 位置的值,并维护 \([mid,i]\) 减法减到的最小值来维护。而所谓减法减到的最小值就是前缀和的最小值。
这样最起码我们可以做 2 log 了。
额,上面这个写成栈了,我们再想想队列怎么做。
额,队列的话,就是你算一下后面减法一共减了多少,然后照样可以二分。
是不是有可能有更好的做法?
~ [JOISC 2021 D1] IOI 热病
你考虑两个人能碰头当且仅当一个人在以另一个人为中心的米形内,并且两人的碰头时间是一个与选择方向无关的数。
你发现,整个传染过程可以被转化成一个有根叶向树的形式,如果你认为边权是两人碰头时间,那么这棵树满足从根到叶子边权严格递增。
当然,这里为了方便,我们要进行拆点。
如果真的给了你一张图和一个根,那么让你求这样一棵生成树应该是可行的。
现在的问题是,你求出来的生成树当中可能包含不同方向的同一个点。这个确实是可以构造出来的。
那我们盲猜一波,我们猜如果一个点有两种情况被包含到同一个决策当中,那其实这个是无所谓的。
接下来的部分参考了 sol。
你考虑枚举 \(1\) 号点初始方向,并把它平移到原点,方向钦定为 \(x\) 轴正方向。
注意到在时刻 \(t\),\((0,0)\) 能影响到的范围至多是 \(|x|+|y|\le t\),并且这个界并不紧。
考虑一个 \((x,y)\),如果它在坐标轴上,那它一定向原点运动。否则因为它逃跑的方向跟上面这个范围的增长方向一致,范围一定追不上它。
如果 \(|x|\neq|y|\),类似地,你会发现它一定是沿着较短轴,朝向原点的方向走。
如果 \(|x|=|y|\),类似地,如果它在一四象限,朝平行 \(y\) 向原点方向;否则朝平行 \(x\) 向原点方向。
现在我们确定了所有点的移动方向,那剩下的问题就是如何求之前说的生成树。
我们参照 Dijkstra 的方式,考虑每次取出最小点,然后更新其它点。如果对每一行、列、对角线、反对角线都开线段树的话,你发现更新操作就是区间对直线 chkmn,那这个我们显然可以李超树实现对吧,查询就是在很多线段树当中取最小值。
写不了一点。
感觉我还是在凭感觉做题。有一个比较严重的问题就是不关注细节,有一些题就是你把细节想清楚之后就能发现一些东西,可能就能继续往下做。而不是你说“感觉”一下这个方向好像比较困难,就不往下想了。
* [JOISC 2021 D2] 逃跑路线
为啥 \(n\le 90\) 啊,那我要随便做了。
你考虑 \(u\to v\) 的过程中可能经过了若干天,我们把它分成三个阶段:时刻 \(t\) 到第一天结束,连续的若干天,最后一天一个尾巴。
你考虑,如果从时刻 \(0\) 开始,只允许走一天,这个显然我们可以对每个点跑 Dijkstra 来算答案。
那其实后面两个部分我们已经会预处理了。剩下的问题是怎么求第一个部分。
简单的想法是你枚举一个 \(k\) 看一下第一天剩下的时间够不够跑到 \(k\),这个怎么算呢?
注意到 \(u\to k\) 想要存在一条道路,那开始时间肯定是越早越好。所以我们记录一个 \(mx_{u,k}\) 表示最晚出发时间,这个显然可以通过二分 + Dijkstra 求出。
那我们就做完了,回答询问只需要枚举 \(k\)。
你发现二分复杂度寄了,同时你发现它很唐,事实上我们可以找到最小的 \(t\),满足加了它之后这个图的边会发生变化。
额上面这东西复杂度不太对。
阅读了 sol。
我们考虑如何计算第一天的影响。我们想知道 \(u\to v\) 在 \(l\) 的限制下能否到达。可以改成以 \(v\) 为起点倒着做,每次更新是 \(d_u\leftarrow\max(d_u,\min(d_v-w,c))\),做一遍 dij 就可以了。
还剩下的一部分是怎么算只用一天的最短距离。你发现如果你有一个真实的最短路,那么你可以枚举这个最短路上的任意一条边,你发现,如果从这条边往后,你把自己当成是 \(c\) 来计算,结果是不变的。
所以你可以枚举 \(u,v,(x,y)\),计算 \(u\to x\),到达时刻为 \(c-l\),\(u\) 最晚什么时候出发,以及 \(y\to v\),起始时刻为 \(c\),最早什么时候到达。
这二者都是方便求的。
这样,对于一组 \(u,v\) 我们得到了 \(O(m)\) 个方案,去除被偏序的部分之后,回答询问时在这个上面二分就可以了。
这个题感觉它的想法就是,因为时间不固定我们是很难做的,所以就想办法,要么把起始时刻固定,要么把结束时刻固定。
[JOISC 2021 D2] 道路建设
经典题。
转切比雪夫,然后我们开一个堆,里头放每个点当前离它最近的点。问题转化成 \(k\) 次询问距离某一个点第 \(p\) 近的,这个可以二分然后变成二维矩形数点。上主席树就行了,总复杂度 2 log。
我们自己写一下曼哈顿怎么转切比雪夫的。
所以转切比雪夫就是 \((x,y)\to(x+y,x-y)\),转回来倒着做就可以了。
[JOISC 2021 D3] 聚会 2
考察怎样的点能成为合法点,显然这些点都是参会者的重心,显然这些点会构成一个连通块,进一步分析发现这些点构成一条链。
那我们考虑一个链 \((u,v)\) 的贡献,你发现当 \(\frac k2\le\min(sz_u,sz_v)\) 时能产生 \(dis(u,v)\) 的贡献。
考虑点分,我们在点分树上更新 \(u\) 的贡献,不妨强制令 \(sz_u\le sz_v\)。你考虑当前枚举到一个 \(l\),如果说另一个端点是 \(v\),那么会对 \(sz_v\ge sz_u\) 的产生 \(dis(u,l)+dis(v,l)\) 的贡献,我们做一个 chkmx 就可以了。
总复杂度 2 log。
其实直接点分治就可以了,总复杂度 1 log。
[JOISC 2021 D4] 最差记者 4
关系连成基环树森林,如果我们知道每个环上的点选或者不选有什么贡献,那我们可以简单做。问题转化成如何对一个树做这个东西。
为了方便,我们按照 \(h_i\) 大小重编号。考虑一个暴力,\(dp_{i,j}\) 表示当 \(i\) 祖先链上选的上一个点是 \(j\) 的时候(不含 \(i\)),\(i\) 子树内的答案。
考虑用线段树维护整体 dp,你发现前半部分就是一个 merge 给它加起来,后半部分是定值,我们先 query 单点求出来,然后是对合并后的一个前缀 chkmx。
考虑一个点维护 \(mx,se,mxcnt\),以及 \(mxtag,alltag\) 标记。chkmx,query 都是好做的,问题是如何做 merge。
merge 你需要考虑两种情况:两个叶子的合并,一个节点跟一个空节点的合并。
前者很简单,后者我们可以考虑空节点的父亲,然后在这个时候直接把空的这一侧当成一个区间加 tag 给它打上去就行了。
事实上我们没必要照搬 chkmx 的这一堆标记信息。因为只有单点查询操作,所以我们可以每个点维护 \(mx,ad\) 表示一次 \(v\leftarrow\max(mx,v+ad)\) 的操作,这标记是方便合并的。
* [JOISC 2021 D3] 保镖
首先,询问很多,但是询问大概率是先挂靠到一个 vip 上面去,后面的情况我们就都清楚了。所以问题主要是怎么预处理出前面 vip 的情况。
我们现在预处理的难处在于,保镖的位置是不好把握的。显然这方面应该要根据贪心的原理进行一些处理,让我们来试一试。
我们不妨从只有两个人的情况来入手。
如果两个人相背而行,那显然我们只有可能在恰好能走到第二个人起点的时候选择是否拐弯。
如果两人同向而行,你发现自从第二个人开始走之后,两个人距离差就不变了,这个时候你写一下如果在 \(t\) 时刻拐弯的贡献,你发现这是关于 \(t\) 的一次函数,正负号由两个人给的钱多少决定。所以,你要么绝不拐弯,要么在一个可以算出来的时刻拐弯。
如果两个人相向而行,那显然我们跟着一直走直到两个人相遇的时候再选跟哪个人走就可以了。
总而言之,我们如果保护的人 \(a\to b\),那么我们可以唯一算出一个最优时间。
再注意到,事实上我们的转移只有 \(O(n^2)\) 种,这样我们大概就可以完成预处理的部分了。
考虑询问的部分。我们大概是先挂靠到一个人身上,然后跟着他直到下一个转移点再考虑要不要跑路。这样的话,一个人就会被分成若干段分段函数。注意到时限是 25s,所以我们枚举一个人然后算就行了。
这东西咋写啊???
阅读了 sol。
我们放到平面坐标系上,你发现一个人变成了斜率为 \(\pm 1\) 的一个线段,然后保镖可以向右上,右下,水平走。
不妨旋转坐标系,变成横平竖直的。保镖可以向右,向下,向右下走。你发现向右下走一定可以拆成向右向下走。
我们把端点离散化变成 \(n\times n\) 网格,我们可以直接算出来走到每个关键点之后的最优方案。
现在给你一个一般的保镖,它一定是先到达一个线段,然后再做。
我们求出来这个保镖有可能到达的竖线/横线,然后李超树扫一遍就可以解决了。
我刚刚说的东西可能有点道理的,就是你发现确实可能的转移只有 \(O(n^2)\) 种,并且这之后确实是一个若干段分段函数。但是那个东西一点都不直观。
[JOISC 2020 D1] 建筑装饰 4
如果没有 \(A,B\) 必须选同样多的话,我们可以大力贪心。具体来说,如果能选 mn 就选 mn,否则选 mx。
然后你看一眼之后发现,前面对后面的影响仅限于最后一个位置是谁,而最后一个位置只有两种情况。所以你可以大力分讨。
经过讨论,我们发现绝大多数情况,前后可以直接独立开,无非就是可能会确定一部分的决策。对于剩下唯一一种无法独立开的情况,是说前面的 \(mn\) 能选后面 \(mx,mn\),前面 \(mx\) 只能选 \(mx\) 这种情况。
这样的东西会形成若干个连续段,对于每个段,我们发现你要是选了一个 \(mx\),后面就都得选 \(mx\) 了,所以一定是先一段 \(mn\) 再一段 \(mx\),所以我们可以算出来它可能产生哪些贡献。
我们发现任何段产生的贡献都是一个区间,所以我们相当于要从每个区间里选一个数,最后这些数加起来要等于一个给定的数。你把上下界调一调这是非常好做的。
所以这好像是线性复杂度?
嗯这就是正解。有一些人是直接打表发现 \(dp_{i,j}=1\) 的 \(j\) 是一段区间,然后就好转移了。不过我这个观点更本质一点。
然后 sol 里有人说可以加强成计数问题。我来想一下。
我们对每个段算一下它得到每个和时的方案数,然后相当于是一个卷积,这个肯定可以分治 NTT 做到 \(O(n\log^2 n)\)。
暴力卷积也可以做到 \(O(n^2)\)。
* [JOISC 2020 D1] 汉堡肉
\(k\) 很小,是不是什么数据结构题。
为啥我连 \(k=2\) 的数据结构都不会做。看了一眼讨论,正解好像是 2sat。想想。
额不会,阅读了 sol。感觉我菜完了啊。
你考虑一维的情况,我们会找到右端点最小的位置去放。二维的情况我们类似,找到右边界最小,左边界最大,上边界最小,下边界最大,这会围出来一个矩形。如果不是矩形的话可以转化成一维情况。
我们选的所有点一定都在这个矩形上,否则可以调整,并且每个边上至少有一个点,否则不合法。
接下来我们考虑搜一搜搜出来每个边上有几个点。然后对于其中一种情况,我们发现,如果矩形含有三个边,说明它完整包含其中一个,已经合法。如果含有两个边,就是限制前后缀,如果含有一个边,就是限制一个区间。这个是容易用 2sat 前缀和建图处理的。
我想的时候很早就有降维的想法,但是当时觉得二维情况很困难,一维情况很难对它有什么价值就没往下想。我也不知道该怎么解决了。
~ [JOISC 2020 D1] 扫除
这是个 ds 题,我们猜一猜可能有点均摊的感觉。
如果只有 H/V 的话,那其实就是前缀 chkmx,单点查询,我们随便做。
我们看一眼 sub3,发现如果满足这个条件,那么操作之后仍然满足这个条件。这个好处就在于我们每次操作的点标号连续,并且两个维度相当独立,我们拆开做就可以了。
看一眼 sub4,发现没有插入操作。
你发现一次操作过后,相当于把一个区域给“扫干净”了,这个区域之后不会再有点需要处理,然后你发现我们可以分成若干个独立的子三角形,并且一次操作只会影响到其中一个三角形。
然后我猜这个时候可以均摊了。因为一个点,在第一次被扫到之后,它和同一拨被扫到的点就“合体”了,之后所有沿着另一个方向扫的都是合并一些点成为一个新的点,所有沿着这个方向扫的都是把它的一个前缀给分裂出去。额我不好说复杂度有没有保证,仔细想了想好像不太行。
或者换句话说,我们发现所有被扫过至少一次的点,都满足 sub3,所以我们考虑把每个点延后到它第一次被扫到的时候再加入,相当于我们对每个点要求它什么时候第一次被扫到,这个是问第一个覆盖它的矩形,我们需要倒着做矩形覆盖,单点查询。
现在相当于动态加点,但是时刻保证满足 sub3 的条件。那我们会做这个问题。
最后,考虑插入操作。我们扔到线段树的 \(\log Q\) 个区间上,每次询问完之后更新当前点的坐标,然后继续下一次询问就可以了。
那么我们就做完了。看了一些 tip,主要是最后一个部分。
[JOISC 2020 D2] 有趣的 Joitter 交友
注意这个关系并不构成 DAG,很简单的例子是你考虑一个 \(k\ge 3\) 元环。
但是你发现对于双向边构成的关系满足传递性,所以我们可以类似地维护一种“等价类”一样的东西。只需要支持合并。
维护等价类里有什么点,类向类,类向点,点向类的连边即可。只需要支持合并,启发式就行了。
2 log。
然后我看了一眼别人的实现,他们都直接按照点集的大小来启发式合并,而不是所有需要进行操作的集合。这真的对吗?
好像是对的。你考虑在最开始的时候就把所有附加的边挂到点上面,这样你一个点会被更新当且仅当它这个部分是小的,这一共只有 \(\log n\) 次。所以总复杂度是正确的。
我们可以说得更普适一点。你考虑有 \(n\) 个元素,每个元素有一个主值 \(a\),一个副值 \(b\),然后 \(\sum a_i=m,\sum b_i=k\),把两个部分合并起来的代价是两个部分主值副值之和。
考虑其中一个元素 \(u\),它会被统计,当且仅当另一个部分的主值之和比它大,所以只会发生 \(\log m\) 次,所以总复杂度就是 \(O((m+k)\log m)\)。
但这个问题当中,除了点以外,别的东西合并之后主值不一定相加,所以不适合当作主值。不过如果我们先离线下来把这些值求出来,然后合并的时候强制相加,那它们也可以当作主值。甚至我们赋一些随机权值也可以。
[JOISC 2020 D3] 星座 3
我们注意到,两个星星可以构成星座,当且仅当它们 \(x\) 坐标范围内 \(a\) 的最大值小于二者 \(y\) 坐标最小值。因此考虑笛卡尔树。
我们进行一个 dp,考虑一个笛卡尔树节点以及它的左右子树,你发现相当于左右子树最多有一个能选 \(\ge a_x\) 的,因此记 \(dp_{i,x}\) 表示 \(i\) 子树内选 \(\le x\) 的答案,只需要支持单点查询,区间加,合并(取 max)就可以了,这是容易用线段树合并实现的。
这个不够牛。
考虑仔细分析一个点,如果它被选了,那么哪些点不能被选。为了方便,我们可以钦定这个点是 \(y\) 较小的点。你发现它会 ban 一个向上的 3-side 矩形,你考虑从下往上 dp,然后发现转移大概可以用什么数据结构维护的。
这个不够牛。
你考虑分析一个点,它被选了之后,哪些比它小的点不能选。发现这是笛卡尔树上的一条链(你把一个点看成掌管一个矩形),所以变成选树上若干不相交链。这个可以 dp 然后用树剖优化转移。
这个不够牛。
有一些什么做法,我没看懂。
[JOISC 2020 D4] 首都城市
就是说树上有颜色,让你选一个最小的颜色的集合,使得点构成一个连通块。
你考虑如果选了一个颜色,为了构成一个连通块,相当于要求还要选一些颜色。这些依赖关系缩点就可以了。
问题变成怎么构出这张图。考虑把一个颜色的所有点都提取出来,我们要向包含它们的极小连通块里的每个颜色连边。注意到为了覆盖这个连通块,我们可以排序之后拆成 \(O(sz)\) 个路径,问题变成怎么向一个路径连边。
这个显然我们树剖就可以了。
[JOISC 2024 D1] 鱼 3
终于更了 2024 的题了。不过这个题当初和 spx 看过。不过反正当初我不会做,现在也基本忘了咋做的了。
我们把操作看成,你有序列 \(c\),可以执行单点减 \(D\),要求最后整个序列是不降的。这样操作之后的代价是剩下的最大值(最后一个元素)加上单点操作的次数。
如果你只关心单点操作的最小值,那你显然是不会对最后一个位置进行操作的。所以我们可以先算这个。
稍等。考虑 \(i,i+1\),要求 \(c_i-x_iD\le c_{i+1}-x_{i+1}D\iff \lceil\frac{c_i-c_{i+1}}{D}\rceil\le x_i-x_{i+1}\),我们的代价是 \(\sum x_i+c_n-x_nD\),这式子一点都不优美,而且解释起来比较复杂,并不适合进行计算。
读错题了,逆天。我们只需要最小化 \(\sum x_i\),这就优雅多了。
那显然我们是会算这个的,只需要令 \(x_n=0,x_i=\max(0,x_{i+1}+\lceil\frac{c_i-c_{i+1}}{D}\rceil)\) 就可以单次 \(O(n)\) 计算。
考虑套到线段树上计算,使用单侧递归线段树。我们记 \(\text{calc}(i,l,r,val)\) 表示节点 \((i,l,r)\) 从右侧给入值 \(val\) 时的答案。发现很难计算。
另外一种思路,我们直接记函数 \(to_i(x),sum_i(x)\) 分别表示当前这个节点传入值 \(x\) 之后变成的数/和。注意到 \(to\) 是由若干段斜率在 \(\{0,1\}\) 内的直线连续拼接起来的,并且段数显然是 \(O(r-l)\) 的。类似地,\(sum\) 也是若干段单调上升的线段拼接而成,它的段数也是 \(O(r-l)\)。所以我们使用线段树维护,跑一遍就可以了,总复杂度 1 log。
我要写得丑一点,用个 set 啥的,复杂度应该是 2 log。
upd:阅读了 blog 发现自己的做法好唐。
你尝试暴力展开 \(x_i\) 的定义,发现是 \(x_i=\max(0,\max(c_i,c_i+c_{i+1}+x_{i+2}))\),那你大概有感觉了,这东西本质上是前缀和 max,写出来就是 \(\max(s_p-s_{i-1})=\max(s_p)-s_{i-1}\),然后使用你喜欢的方式维护就可以了。
[JOISC 2024 D2] 桌游
我们先把问题简化一下,把停止点作为关键点,预处理出所有关键点对之间的距离,以及预处理出任意点到任意关键点之间的距离。
先考虑 \(2\sim k\) 的人会怎么移动。如果它们已经知道自己要移动共 \(x\) 个回合,首先显然每个人的移动策略是独立的,然后它们第一个回合一定是从目前点 \(u\) 移动到某个关键点 \(v\),之后 \(x-1\) 个回合都是在 \(v\) 以及离它最近的关键点之间移动,显然这个距离是 \(1/2\)。所以我们取出离 \(u\) 最近的一个答案是 \(1\) 的 \(v\),以及一个答案是 \(2\) 的 \(v\),这样贡献就是两条直线,显然我们会取 min,我们把 \(k-1\) 个人的贡献全都加起来,就可以得到总贡献,显然这个贡献是一个上凸函数 \(f\)。
接下来考虑 \(1\) 的决策。考虑一个 \(1\to T\) 的路径,显然我们有两个参数 \((sum,round)\) 来评定它,即这个路径的长度和这个路径上关键点的个数。最终的答案其实是 \(sum+f_{round}\)。如果记关键点个数 \(\le x\) 时路径长度最小值为 \(s_x\),那么要求的就是 \(s_x+f_x\) 的最小值。因为 \(x+1\) 至少导致 \(f+k-1\),所以 \(x\le \frac n{k-1}\)。
这是一个单调不增的函数和一个上凸函数的和,这上凸函数是若干段分段函数,每段都是斜率在 \([k-1,2(k-1)]\) 的线段。
记 \(dis_{u,x}\) 表示 \(1\to u\) 经过了 \(x\) 个关键点的答案。显然这可以理解为在边权为 \(1\) 的分层图上跑最短路,复杂度 \(O(\frac{n^2}{k-1})\),别的地方显然起码能做到这个复杂度。所以我们现在会一个平方做法。
我觉得性质分析得挺不错的了。但是 \(f\) 是凸的并没有用上,以及我感觉这个 \(k\) 好像可以根号分治一类的,目前还不会一个跟 \(k\) 复杂度正相关的做法。
瞄了一眼 sol,发现复杂度确实是根号的,做法确实是根号分治。
额发现我有点唐诗了。你对每一段一次函数分别来算,这个时候相当于每走一个关键点就额外产生 \(c\) 的贡献,然后你把前面那些少算的提前给补上,后面多算了无所谓,反正不会更优秀。这样只需要做 \(O(k)\) 次就行了,复杂度可能是 \(O(nk\log n)\) 一类的东西。
总之最后复杂度是根号或者再带个 log。其实是简单题,上面那个做法早就想出来了,但是一直觉得前面那些东西是减,会算出不合法的答案。
[JOISC 2024 D2] 有趣的家庭菜园 5
我们先解决一个子问题,给你两个序列 \(A,B\),不妨假设它们已经排好序了,要让你找一种配对方式,使得 \(\max(|A_i-B_i|)\) 最小。
我猜测直接按照排序的顺序配对就行了。事实表明确实如此。你只需要把 \(n=2\) 的几种情况全都讨论完,然后对任意两个都应用你的结论就可以得到这个性质。写了个暴力这东西是对的。
然后我们看一眼 sub,发现哪怕你对整个序列所有数的大小关系了如指掌,你也不会做。
换句话说,给你一个长度为 \(2n\) 的序列 \(A\) 和一个长为 \(n\) 的序列 \(B\),它们都是排好序了的,然后 \(B\) 是个滑动窗口让你去匹配,问你最少代价是多少。
这直接算相当难算啊,哪怕让你算 \(\max(A_{i+l}-B_i)\) 都不好算。
你考虑二分一个答案 \(mid\),这样的话 \(B_i\) 就能匹配 \(A_x\in[B_i-mid,B_i+mid]\) 的 \(x\),这样的 \(x\) 显然是一或二个区间,我们就可以算出来偏移量的区间,也是一或二个。这样类似于整体二分的做法,显然是不行的,因为它可能存在 \(n\) 个分界点,你为了算出来这些分界点,每个位置至少要算一次,这就已经是平方的了。
不过这个过程是可以加速的,你没必要对每个 \(mid\) 都扫一遍整个序列。事实上你可以算出一些 min 啊 max 啊一类的东西,就可以了。因此这个做法还是有点救的。
但是你有点太糖了,我们并不是要求出所有的值。事实上我们对两种颜色同时进行二分答案,我们只是想知道有没有合法解,这样就能判断了。
你想想一下,一个 \(i\) 的 \(|A_{p_l(i)}-B_i|\) 图像大概是什么样子的。在有性质的时候,这图像是一个 V 字形,因此我们可以像刚刚那样做。
考虑没有性质的时候,这图像是什么样子。
你发现,它是先平一段,然后你的匹配点不断右移,这样,这图像仍然可以看作是 V 字形,因此我们仍然可以二分。
写起来细节非常多,根本不想写。
[JOISC 2024 D3] JOI 之旅
先研究不带修改。
肯定考虑枚举中间点,然后分讨另外两个点在树上的位置,如果记三类点子树和为 \(sz_{A/B/C,*}\),记 \(f_u=\sum_{v\in son(u)}sz_{A,v}sz_{C,v}\)
写了暴力,这是正确的。
\([tp_u=B]Asz_{C,u}\) 这部分是方便维护的,唯一的问题就是 \([tp_u=B](sz_{A,u}sz_{C,u}+f_u)\) 怎么做。
\([tp_u=B]sz_{A,u}sz_{C,u}\) 也不难做,问题是怎么做 \([tp_u=B]f_u\),或者说,我怎么做单点询问。
感觉好像变成了这么一个问题,你有两个序列 \(A,B\),需要支持两种操作,一种是 \(B\) 序列区间加,一种是选一个区间,把 \(B\) 序列对应位置加到 \(A\) 上头。
经过研究,这个东西确实是可以做的。所以我们套个树剖上去,就成了 2 log 了。
[JOISC 2024 D3] 塔
塔塔开!
按照可走与不可走,把位置划分为若干段,因为我们有 \(+1\) 操作,因此每段可走段内真正能到达的区域是一个后缀。这个不可达的前缀我们其实可以等价地看作不可走点。
根据 \(DA\) 与 \(B\) 的大小关系,我们可以把最小化费用的目标分成两类:尽量用 \(+1/+D\)。
你考虑两个 \(dp\) 分别记录使用 \(+D\) 的次数的 min/max。然后经过一些观察,发现取 min 的时候这东西完全是平的,顶多在两个不同段之间会稍微改一下。取 max 的时候这东西就是阶梯型。所以你稍微维护一下怎么做都行。
[JOISC 2024 D4] 逃跑路线 2
喜报,逃跑路线 1 我现在似乎不会做了!!!
但是这个题并不是很难。还挺有意思的。
注意到,我们要从 \(L\to R\),如果我们确定了这个路上,任意一个要走的航线,那么我们往前往后要走的航线都是确定的。所以,只要这个区间内的 \(min(M)\) 比较小,那我们就可以这样倍增来做。
考虑另外一种当区间内的 \(M\) 都很大的时候的做法,显然这样的询问,它的 \(R-L\) 不能很大。并且这样的询问种类总数其实也不多。\(R-L\) 不大,就说明它经过的天数不会很多。
额有点太糖了,这部分也很简单。我们考虑枚举一个航线,然后往后暴力跳 \(B\) 步,这样就把长度短的给处理掉了。
最后复杂度大概是 \(O(n\sqrt{n}\log n)\)。
[JOISC 2024 D4] 环岛旅行
给一棵树,每次可以询问距离 \(u\) 第 \(k\) 远的是哪个,距离相同按编号顺序排序。你要在 \(2n\) 次询问内还原这棵树。
\(n\le 300\)。
看起来挺经典的。但是这种交互很让我头疼。
是不是我们先假装询问了所有能询问的东西,那现在就是每个人手里头有一个序列,这个序列里头最近的肯定有边对吧。这样连出来若干个基环树,每个基环树的环都是二元环。考虑怎么把这若干个连通块搞起来,说白了就是你想让每个边都至少能被算到一次。
考虑 \(u\) 询问得到的这个序列,如果这个序列某个位置下降了,那说明跟 \(u\) 直接相连的一定在这个位置之前。但是这个位置之前的跟 \(u\) 的距离不一定都是 \(1\),但是如果跟它的距离不是 \(1\) 的话,比方说我们考虑第一个距离是 \(2\) 的点 \(v\),它们之间的连边是 \(u\to w\to v\),那显然
这个题说起来有点复杂,大概思路就是,你通过阅读部分分,发现可以 \(n\to 1\) 依次确定每个点跟哪些点有连边,这样一条边会被算两次,再算上每个点会算错一次,所以复杂度是 \(3N\)。
为了降到 \(2N\),算错一次基本上是没办法优化的,所以要让每个边只算一次。我们钦定在更大的那个点处算,然后有一堆细节,但是反正能做。
~ [JOISC 2024 D4] 乒乓
你要构造一张 \(n\) 个点的竞赛图,满足其中恰好有 \(m\) 个三元环。
\(n\le 5000\)。
额不是很会,弃了。
滚去学了一些竞赛图的内容,现在我是竞赛图领域大神!!!
滚回来写这个题了。
首先三元环可以考虑反面,我们在那个有两个出度的位置统计贡献。这样,记出度序列是 \(s_i\),那么贡献就是 \(\sum\binom{s_i}2\)。
简化一下,现在我们有 \(\sum s_i=\binom n2,\sum s_i^2=lim\),以及还有关于 \(s_i\) 排序之后的一些限制。
我们考虑类似于兰道定理的证明过程,从一个平凡的 \(s\) 一步步调整到我们想要的结果。
首先,取 \(s=(0,1,\dots,n-1)\),显然此时贡献取到最大值。我们接下来的任务就是向小调整。
注意到两个数 \(x<y\) 变成 \(x+1,y-1\),此时的贡献增量 \(\Delta=-2(y-x-1)\),那显然我们要让 \(y\ge x+2\) 贡献才会发生变化,并且一次变化 \(-2\)。
这里已经牵扯到一个奇偶性问题了,不过通过分析之后发现恰好不用考虑奇偶性问题。接下来变成了我们需要进行 \(lim\) 次 \(-2\) 操作。
考虑我们每次恰好取相差为 \(2\) 的一对 \(x,y\),因为前面的一直在变大,后面在变小,所以 \(\sum_{i=1}^ks_i\ge\binom k2\) 一直是满足的,我们只需要注意保持 \(s\) 的有序性。
然后你发现确实有这么一种方法来不断调整,你照着这个做就完了。
剩下一部分是怎么根据 \(s\) 构造一个图出来。如果你直接根据兰道定理的证明来做,复杂度是 \(O(n^2(\frac nw+\log n))\)。
我们有更好的构造方式,考虑增量法。
我们考虑确定 \(s\) 最大的那个点 \(n\) 的所有连边,显然我们可以让它向 \(s\) 最小的 \(s_n\) 个点连边,然后让剩下的点连向它,并相应修改它们的 \(s\),然后重新排序。
向 \(s\) 最小的点连边,是为了不减小这些 \(s\),使得 \(\sum_{i=1}^ks_i\ge\binom k2\) 仍然成立。
这部分复杂度是 \(O(n^2\log n)\),所以总复杂度也是。
这个题很不错。

浙公网安备 33010602011771号