record 4.15-4.19
~ CF1954 F
不是这啥东西啊,为啥 edu 的 f 放这么困难一个题。
一句话题意:让你计数本质不同的,长度为 \(n\),含有 \([c,c+k]\) 个 \(1\) 的 01 串,其中要求至少有 \(c\) 个 \(1\) 是挨着的,其中本质不同指的是写成环之后旋转不同。
我们发现,两个条件都不是特别好处理。我们先考虑后一个条件,写成环之后旋转不同。我们把问题简化成长 \(n\),含 \(c\) 个 \(1\),旋转本质不同。
一个思考角度是先想我们会算什么。我们会算一个不要求旋转不同的 01 序列的个数。你考虑这样多算或者少算了什么,发现如果你打算最后除以 \(n\) 的话,相当于是少算了一些部分。具体来说,如果有一个最小循环节是 \(l\) 的填法,那么它应该被算 \(\frac nl\) 次,但是事实上只算了 \(1\) 次。
那你发现这其实就是 Burnside 引理。
接下来相当于我们把旋转不同的条件,转化成了已知有长为 \(l\) 的循环节。
首先如果 \(l\neq n\),那么我们可以统计单个循环节的 \((l,r,mx)\) 这些参数,要求相当于是 \(\max(mx,l+r)\ge c\),我们可以通过枚举 \(l+r\) 一类方式转化成要求中间部分有 \(c\) 个 \(1\) 是挨着的。这就转化成了序列上的问题。
额但是你发现如果 \(l=n\) 的话,这个环最后挨到一起的部分是很难处理的。我们不妨直接用原问题的描述,我们要求第 \(1\sim c\) 位都是 \(1\)。
在这个条件下,如果 \(l\le c\) 都是平凡情况;如果 \(l>c\),是不是很好做的。
那是不是做完了?我看看。
额不对这个是错的,因为 Burnside 引理当中要求你的映射在置换的作用下封闭,而这个显然是不封闭的。
额你发现 \(l=n\) 的 case 其实你仍然可以枚举 \(l,r\) 然后类似地做一做,所以我们来写一下吧。
而
其中 \(dp_{n,x}\) 表示长为 \(n\) 的 01 串,含有 \(x\) 个 \(1\),其中至少有 \(c\) 个连续的 \(1\)。
然后你发现里面的第二个 \(\sum\) 都是前缀和的形式,并且都可以预处理出来,所以你就做完了。
只剩下一个问题:怎么算 \(dp\)。
可能有一些容斥做法,但是最简单的是考虑反面。我们记 \(f_{n,x}\) 表示长为 \(n\),含有 \(x\) 个 \(1\),其中不存在 \(c\) 个连续的 \(1\),并且结尾是 \(0\),然后这个转移你就每次转移一个 \(1\) 的连续段,可以前缀和优化做到跟状态同阶的复杂度。
然后 \(dp_{n,x}=\binom{n}{x}-\sum_{i=0}^{c-1}f_{n-i,x-i}\),你发现这个是对角线求和,额你如果乐意的话可以把状态改成含有 \(x\) 个 \(0\),这样就是前缀和了,但是无所谓。
总之我们大概是做完了。这个题感觉也不是很困难,场上比较摆,时间可能也不是特别够。
CF1956 E1&E2
场切了 E2/kuk,但是 E1 fst 了,怎么会是呢?
你发现这个操作很复杂,但是我们询问的是进行很多次操作之后,最后每个位置是否是 \(0\)。所以你可能要考虑一些长期影响,并且你可能需要把视角聚焦到某一个元素的变化情况上。
先发现一些没啥用的小性质:最后如果 \(i\) 位置留了下来,那么 \(i-1,i+1\) 肯定留不下来。
这个题其实有一点均摊的感觉,你先猜总操作次数不会很多。但是这是假的,考虑 \(1,1e5,1,1,1e5,1,1,1e5,\dots\),这个操作次数可以很多。
但是你发现,这个操作一轮之后,其实就是前者一直减后者直到减干净为止。那如果我们特判这种情况,剩下的部分操作次数是不是不会太多。
你考虑四个数 \(a,b,c,d\),其中 \(a\to b,b\to c,c\to d\) 有贡献的减法分别有 \(k_1,k_2,k_3\) 次,并且 \(k_2>k_1,k_3\),我们想说明的是,\(k_1+k_3\) 不会太大。
你发现 \(b\ge k_1,c\ge k_1k_2,d\ge k_1k_2k_3\),而 \(k_1k_2k_3\le d\le V\),所以 \(\min(k_1,k_2,k_3)\le \sqrt[3]{V}\),也就是说我们先操作 \(O(\sqrt[3]{V})\) 次,然后剩下的非 0 段长度至多是 \(3\),这是可以特殊考虑的。
CF1956 F
这个题场上好像也没几个人过。
一句话题意:点编号 \(1\sim n\),每个点有参数 \(1\le l_i\le r_i\le n\),\(i,j\) 之间有无向边当且仅当 \(|i-j|\in[l_i+l_j,r_i+r_j]\),问连通块个数。
首先看到绝对值我们非常难受,忍不了一点,直接拆开!
变成 \(i>j\) 时 \(i-j\in[l_i+l_j,r_i+r_j]\),\(i<j\) 时 \(j-i\in[l_i+l_j,r_i+r_j]\),你拆拆拆发现变成三维偏序反正就是很寄。
但是你通过图像/代数方法,你发现 \(i>j,i<j\) 的限制时没有用的,总之就是要求 \(i-j\in[-r_i-r_j,-l_i-l_j]\cup[l_i+l_j,r_i+r_j]\)。这样拆拆拆看起来就是个二维偏序。
但是如果你把图像画出来,你发现这个就是 \(j\) 在往右/左,\(i\) 在往左/右够,如果两个人能牵手成功,那么它们之间就可以连边。
如果你直接连的话,你会发现一个问题:比方说两个人同时往左够,但是他们够到一块了,这个本来不应该算的,但是还是算了。
所以我们要尝试规避这个问题。一个可行的方式是拆点。
我们拆出两排点出来,上面一排只会有从左往右的边,下面一排只会有从右往左的边,这样,我们可以保证,如果两个人在原图上有边,那么它在新图上强连通。如果说两个人在新图上强连通,那么说明存在一条 \(a\to b\) 的路径,总之就是很对的。
所以我们建图,缩点,然后求有多少个强连通分量当中包含原图的点就可以了。
建图自然是线段树优化建图。
这个题的整体思路应该是,先发现是个问你连通块数量,然后问题就是分析这张图的性质。你发现这个边可以通过一些简单的方式表达出来,然后就做完了。其实另一个方向就是高维偏序。
upd:
sol 给出了一个 \(O(n)\) 做法。还是考虑那些被算错的人,你发现,当我们把那些只能被人向右/左到达的中间点删掉之后,就是对的。
然后事实上我们没必要线段树优化建图。因为我们只关心连通性,所以如果 \(v\to[x,y]\) 可以转化成 \(v\to x,x\to x+1,\dots,y-1\to y\)。
可惜的是有向图似乎没办法这么做。所以我们上面东西的空间复杂度是 \(O(n\log n)\) 然后常数大得一坨,总之空间过不了一点。
无语了,一直写不过。弃了。
未名9#R1 B
这个本来应该切了,但是为什么要求至少一个不同的啊啊啊啊啊啊啊啊啊啊啊啊啊/fn/fn/fn/fn/fn/fn,导致我没来得及写 C。
你首先想想你会做什么。如果说我钦定一些位置是相同的,然后剩下位置不做要求,你会算。那你外头套个容斥就会了。
然后你发现 \(n\le 10^11\) 时,\(\max(d(n))\le 4000\) 左右的样子,所以暴力做一些 dp 就行了。
额 sol 是写出一个 dp 出来,然后尝试降低枚举量,拆一拆发现可以写成高维前缀和形式就做完了。
未名9#R1 C
让我写写,看看跟 sol 做法一样不一样。
处理一次询问的时候,你肯定不能一个学生一个学生地来。而你关心的其实是每个小班最后剩多少个名额,所以你可以考虑以小班为主体。
那你比方说第一轮当中,肯定是每个小班先把能塞进来的,第一志愿是它的学生按顺序塞进来,塞不进来的就放那。然后进行第二轮,把剩下的学生当中,第二志愿是它的按顺序塞进来,以此类推。
我们尝试维护这个过程,注意到,我们可以把志愿情况相同的学生分成一类,这样,相同情况的,一定是排名高的先进来,所以每一类这里有一个分界点,我们就这样维护了剩下的学生。
问题是,考虑一个小班某一轮当中,它怎么知道该录取哪些学生。很简单,二分就好了。
这样你做一次的复杂度大概是 \(O(m!m\log^2 n)\),可能能做到 1 log。
额 sol 做法感觉跟我本质应该没啥区别,不过它更好一点。它是基于只会有 \(m\) 次可以进入的小班集合变化,然后直接线段树上二分这个东西。
* [省选联考 2024] 魔法手杖
这个我场上写的那个东西,其实稍微改一下就是 2 log 做法。
具体来说,我们二分答案 \(lim\),由于 \(a_i+x\ge a_i\oplus x\),所以 \(x\ge\max_i(lim-a_i)\),然后就转化成了,有一些数支付 \(b_i\) 代价可以被忽略,然后要求选一个满足条件的 \(x\),使得未被忽略的数异或满足要求。
我们在 Trie 树上做 dp,具体来说 \(dp_u\) 表示为了让 \(u\) 子树内满足条件,至少要支付多少代价。
但是 2 log 显然过不去。
我们猜测你需要把最开始的那个二分给揉到找答案的过程当中。
通过阅读 sol,我们可以得到这么个做法。
你考虑一个 \(\text{solve(u,m,x,lim)}\) 表示只考虑 \(u\) 子树内,费用上限是 \(m\),当前有一个 \(x\),要求 \(x\ge lim\) 的最好答案,
我们先假定 \(u\) 的两个孩子都存在,然后分这一位上 \(x=0,1\) 两种情况来讨论,判定 \(ans\) 的这一位有没有可能是 \(1\)。
如果 \(x=0\),那为了让这一位是 \(1\),首先左儿子必须都花费用,然后我们会对 \(x\) 有一个限制。如果这些限制都能满足,那就说明 \(ans\) 这一位可以是 \(1\),我们递归到右儿子。如果 \(x=1\) 同样有一个判定条件,我们递归到左儿子。
如果判定条件无法满足,那就说明这一位只能是 \(0\) 了,我们仍然可以递归到左右儿子。
感觉这个题是不是不怎么难。/fad
那为啥我没做出来呢。
? 一个题
给你一个序列 \(a\),你现在可以把相邻两个相同的数进行合并,合并之后得到的新数是原数 \(+1\)。
定义 \(f(a)\) 为 \(a\) 序列通过若干次操作能得到的最大值的最大值。
现在你要支持单点修改,以及查询 \(f(a[l\dots r])\)。
\(n,q\le 10^5,1\le a_i\le 10\)。
你发现这个合并的结构写出来是一种特殊的二叉树,虽然并没有用处。
你发现把 \(a_i\) 看成 \(2^{a_i}\) 之后,能合并出 \(v\) 的区间 \([l,r]\) 的必要条件是 \(sum(l,r)=2^v\)。这样的区间只会有 \(O(n)\) 个,但是你发现修改一次涉及的区间变化太多了。
你发现能合并出 \(v\) 的区间一定不会互相包含,只会相交或相离。
如果给你一个区间 \([l,r]\) 让你判定能否构出 \(v\),你可以从左向右,可能有一个类似于在二叉树上搜索的 \(O(r-l)\) 算法。
[NOI 2023] 贸易
写这个题是为了缅怀当时忘记了这个树是一个完美二叉树的自己。
我们观察 \(x\to y\) 的最短路长什么样子,你发现一定是先向上走到 \(lca(x,y)\),然后再往下跳到 \(y\) 子树内部。
重点在于,我们一定不会向上走到超过 \(lca\) 位置。所以,对每个 \(x\) 我们都可以枚举它的 \(\log n\) 个祖先来统计答案。
对于向下跳的部分,你发现这个比较复杂,直接 Dij 跑一遍就得了。
额,上面的部分在瞎扯。
你发现,\(x\to y\) 最短路一定向上走到至少 \(lca(x,y)\) 位置,之后可能继续向上走了一段,然后再向下跳到 \(y\) 子树内部,再向上跳到 \(y\)。
后面这部分我们是不好处理的,但是我们直接把 \(lca(x,y)\to 1\) 以及 \(lca(x,y)\) 不含 \(x\) 的那个子树加入 Dij 当中跑一遍就可以得到答案了。
唉,当时要是写了这个题就 Ag 了。
[NOI 2023] 字符串
这个题好像也不怎么难啊。
你考虑这个询问没啥用,其实就是想让我们找符合条件的 \((i,j)\),满足 \(s[i,j-1]<s[j,2j-i-1]\),我们把它的结构说清楚之后,询问一般都没啥难的。
怎么描述合法 \((i,j)\) 的结构呢?我们肯定要选用一些字符串数据结构。你可以考虑到比较这两个字符串的字典序实质上是比较 lcp 之后的第一个元素,然后做一些什么东西的。
但是一个更自然的想法,是直接比较 \(i,j\) 两个后缀的字典序,然后通过判断它们的 lcp 与 \(j-i\) 的关系来判定这样的 \((i,j)\) 是否真的合法。
很显然这是 sa,\(i,j\) 合法当且仅当 \(j-i>\min(h[id_i],\dots,h[id_j])\)。
然后可能一个想法是在笛卡尔树上做一些什么东西的,但是发现在笛卡尔树上似乎只能把一次询问拆成 \(O(n)\) 个询问,这是不优的。
我们考虑回过头来,看看询问满足什么形式。你发现一次询问事实上是固定了 \(i\),然后询问一个区间内的 \(j\),这个关于每个 \(i\) 而言是相当独立的,所以我们的一个想法就是离线下来,然后用数据结构维护 \(i\) 这一维,我们去扫 \(len\) 这一维。
那你考虑当 \(len\) 这个长度被加入进来的时候,发生了什么变化。你考虑所有满足 \(j-i=len\) 的 \((i,j)\),它合法当且仅当区间 \([i,j]\) 最小值 \(<len\)。
额上面这个东西并不能做,我们考虑换一些方式。
严格来说,\((i,j)\) 合法当且仅当 \(i<j,id_i<id_j,j-i>\min(h[id_i],\dots,h[id_j])\),这是个若干维偏序的形式。
你真的把 sa 写出来看一下,就会发现,如果你按照 \(id_i\) 的顺序来从大到小枚举 \(i\) 的话,那首先 \(id_i<id_j\) 的条件无关紧要了,我们看一下最丑的 \(\min(h[id_i],\dots,h[id_j])\) 这一坨,你可以用单调栈,变成若干次区间加减操作,这个应该是可以用平衡树维护的,但是好像有点太丑了。
好的,读错题了。
大眼一扫,仍然可以在 sa 上做前一部分,但是我们这次要去除的不合法部分变成了一个回文串。然后你考虑什么时候一个中心为 \(p\) 半径为 \(s\) 的回文串可以对询问 \((i,r)\) 产生贡献,你发现这是个二维数点,然后随便做一做一类的就可以了。
额我好像不太会 sa,让我努力编一编。
好像有 bitset 做法,等我写完看看。
额确实可以。发怒发怒发怒。

浙公网安备 33010602011771号