CFの题 Ⅱ
CF512D
首先,显然环上的点没有贡献。所以最后有用的点会形成一个森林。显然可以把每棵树当成一个物品做背包。难点在于如何统计一棵树“每次删一个叶子,指定长度的合法操作序列”,毕竟对于一个点,合法的序列可能是先删子树外的点,然后再删自己。所以可以枚举最后一个删除的点,把无根树问题转化成有根树问题。发现每种方案可能会被算重,令树的大小是 \(x\),选择了 \(i\) 个点,发现当钦定的最后那个点不在集合内时会被算重,所以要除以 \(x-i\)。最后就是要注意如果一棵树有和环相连的部分,那么这个点是最后被删的,直接当有根树做即可。
CF1503D
很巧妙的一个题。首先存在合法方案的必要条件是 \(\forall x\ne y,[a_x<a_y]\ne[b_x<b_y]\),可以适当弱化限制成 \(\forall x,\min(a_x,b_x)\le n,\max(a_x,b_x)\ge n+1\)。发现后面的条件可以使得序列变成 \(f,f_{a_x}=b_x(a_x\le b_x)\)。会发现最终的方案,单增的那个部分应该是前面一段单增的 \(a\),后面一段单增的 \(b\);单减的部分同理。把后面那个部分翻转一下也变成了 \(a\) 单增,\(b\) 单减,于是问题就转化成了希望把 \(f\) 拆分成两个子序列,每个子序列都单减。
有线性做法如下。贪心地维护两个栈,如果当前点小于第一个就丢到第一个里,如果小于第二个就丢到第二个里,这样会出现一个问题,如果一个点可以同时符合两个要求那么随机选可能就不是最优的了,所以有一个方法是说对于位置 \(\text{preMin}_x>\text{sufMax}_{x+1}\) 的 \(x\) 而言,可以把序列拆分开来,每一段之中的决策是唯一的,段和段之间互不影响(可以感性理解一下)。于是对每一段贪心处理后加起来即可。注意无解的判断。复杂度线性。
CF521E
CF316D3
柿子题。如果没有 \(2\) 点的话那么就可以用 \(f_x\) 代表 \(x\) 个人的方案,考虑这个人的球最后去了哪里,有在自己手上和去到之前某个人手上两种可能,所以有 \(f_x=f_{x-1}+f_{x-2}\times (x-1)\)。考虑如何拓展到有 \(2\) 点的情况。强制每个 \(2\) 的人用掉一次机会,显然最后 \(1\) 的人数不变,而那些人的方案是 \(\prod\limits(m-i+1)\),乘起来即可。
CF527E
每个点出入度都是偶数转化成每个点的度数都是偶数,然后发现这是存在欧拉回路的充要条件。于是想到构造一个欧拉回路。常用方法是说给奇数点之间连边(一定会有偶数个),然后就跑一次即可。构造上可以考虑给路径上某奇偶性相同的点集搞外向边,剩下的搞内向边,这样可以保证点在路径序列中每次接受的贡献只会是 \(0\) 或 \(2\)。路径的起始点(也就是终点)不满足这一定律要特判一下。
CF547D
以横坐标和纵坐标为点建立二分图,平面上的点是连边。建立虚拟点,度数为奇数的点连接到虚拟点,这样可以保证图中存在欧拉回路。按回路中边的方向给对应的点染色,由于每个点最多向虚拟点连一条边,而入边等于出边,所以可以保证红蓝边数量之差不超过一。然后就可以了,复杂度线性。
CF547E
AC 自动机的一个应用。离线询问,把询问拆成两个问题,分别回答。对所有模式串建立 AC 自动机,给所有可能到达的点打上标记,一个点可以通向一个模式串当且仅当这个点在 fail 树上是该串尾点的子树之内,单点修改区间查询即可。
CF559E
很巧妙的一道题。用 \(f_{x,y,0/1}\) 代表前 \(x\) 条线,最右边的是第 \(y\) 条,这条线的方向确定时的最大贡献。定义一个点的贡献地方是这条线的左端点位置,所以可以枚举下一条贡献边是谁,这条边设为 \([l,r]\),之前的右端点设为 \(p\),那么这条线的贡献是 \(\min(r-p,r-l)\)。有一种思想是既然我们钦定当前的边是左端点最左的了,那么剩下的边应该贪心地向右摆放,这样一来状态应该形如 \(f_{x',y',0/1}\),贡献是 \(\text{mx}-r+min(r-p,r-l)\) 了。
CF1476F
很巧妙的一道题。用 \(f_x\) 代表前 \(x\) 个灯笼最多能覆盖多长的前缀。考虑当前这个灯笼的方向。如果朝右,那么需要看一下左边的灯笼是否能覆盖到自己,如果可以的话答案就是 \(\max(f_{x-1},x+len)\)。如果向左,由于 \(f\) 具有单调性,可以二分出第一个可以覆盖到 \(x-len-1\) 的点 \(p\),那么 \([p+1,x-1]\) 中的点就是可以随意定向的,贪心地向右覆盖,于是答案是 \(\max\limits_{i=p+1}^{x-1}a_i+len_i\)。输出方案,记录一下转移点即可。
CF611H
一道比较综合的题目。首先有一个结论,钦定每种颜色内有且仅有一个关键点(方便起见定为 \(10^k\)),那么存在一种构造方式使得每一条边的两个端点中至少有一个关键点。证明上可以考虑对于边 \((x,y)\),如果两个点都不是关键点,那么把其中的一个调整为关键点不会影响树的性质。
然后发现把关键点提取出来形成的子图一定是一棵树。由于关键点的数量非常小,所以可以采用枚举 prufer 序列的形式来枚举这个树的形态。然后抛去这些边会剩下一些边和一些点。每条边从源点连一个容量为剩下的数量的边,每个点向汇点连一个容量为剩下的数量的边,中间对应的边点之间连无限边。跑网络流,相当于是在考虑是否存在合法匹配(因为剩下的边都只有一个关键点),如果能跑满就说明存在合法解,在参量网络上找流量即可。点数很少,跑着自然比较快,对于我这种网络流跑得非慢的蒟蒻来说比较友好。
CF576E
一个线段树分治的应用。仍然是经典的二分图判断问题,只需要对每种颜色分别开一个并查集来维护点和附加点的联通状态,然后在遍历到一个点的时候判断一下当前边是否会改变颜色,然后求出颜色之后在下一个位置到下一次出现的位置这个区间内给这条边染色即可。比较卡常和卡空间交了一车才过(可能是我代码能力太弱了),vector 能不用尽量不用(特别是要开 \(10^6\) 级别的前提下),要按秩合并否则会被卡,并查集内栈不能开满(甚至用 stack 都会好上很多),等等等。反正就是一堆细节。
CF916E
一道树链剖分的好题。首先不需要 LCT,事实上能不能跑过去都是个问题。巧妙之处在于在不改变树的形态的前提下,如何把新树上的子树操作转化成原树上的操作。首先可以建立新树上子树和原树上节点的对应关系。设新根是 \(R\),新树上的子树根是 \(x\),然后分类套路:若 \(R\) 和 \(x\) 树没有交集,那么直接对应过来即可;若 \(R=x\),那么子就是整棵树;否则就是整棵树减去根所在的子树。然后一个就是求新树上 \(x,y\) 的 \(lca\),一个显然的结论是这个点是路径 \(x,y\) 中离 \(R\) 最近的点,画个图就知道应该是 \(lca(x,R),lca(y,R),lca(x,y)\) 中最浅的那个。最后就是常规地用线段树维护即可(要用树状数组也不是不可以)。
CF835E
没什么新意的题目。\(1000\) 的数据范围配上 \(19\) 次询问加上希望找到两个数,实在没什么意思。
CF546D
一道没啥意思的题目。显然取质数会比取合数更优,所以问题可以转化成求 \(\prod\limits_{i=l}^ri\) 的质因数个数的形式。显然可以用前缀和来维护。在线性筛的过程中顺便记录每个点的质因数个数即可。
CF605E
一道很好的期望题目。用 \(E_x\) 代表 \(x\) 到终点最优决策下的期望长度。然后进行 \(n\) 轮,每轮找出期望值最小的点,显然它不会再被其它点更新了(毕竟再去其它点肯定不会更优)。然后令 \(p_x\) 代表目前为止这条边没有很优的出边的概率,那么截至目前,每个点的真实期望应该是:
按照这个规则就可以选出当前拿来更新其它点的最优点了。然后就是更新部分,假设 \(x\) 点要去更新 \(y\) 点,那么有一些值会产生变化。首先 \(y\) 被更新的概率是 \(p_y\times e_{y,x}\),所以说呢 \(E'_y\leftarrow E'_{y}+p_ye_{y,x}(E_x+1)\),同时呢 \(p_y\leftarrow p_y\times(1-e_{y,x})\)。复杂度是 \(O(N^2)\) 的。
CF1156F
显然用 \(f_{x,y}\) 代表选出来一个以 \(x\) 结尾、长度为 \(y\) 的串的概率。显然有 \(O(N^3)\) 的做法:
发现系数只和 \(x,y\) 有关。所以对 \(f\) 做前缀和即可。然后就是 \(O(N^2)\) 的了。
CF914F
用 bitset 乱搞的题目。首先对于每个字符维护一个 bitset 表示其出现的位置,然后呢一个结尾是合法的的必要条件是说这个点往前走某些个位置应该是某个特定字符,所以可以考虑枚举给定字符串中的字符,然后把对应字符的位置集合右移某些位然后和初始值全真的 ans 按位与,最后统计答案即可。复杂度 \(O(\frac{|s|\sum|t|}{\omega})\),实际跑得比较快。
CF348C
CF348D
一道比较妙的容斥题目。主要是看了半天 LGV 引理没有非常看懂于是摆了。显然如果没有不交的限制的话答案应该是 \(f_{(1,2)\rightarrow(m-1,n)}f_{2,1\rightarrow(m,n-1)}\),然后发现每一种有交的方案都可以映射成 \(f_{(1,2)\rightarrow(m,n-1)}f_{2,1\rightarrow(m-1,n)}\),减掉即可。有点像卡特兰数路径计数的那个思想,但不完全像。
CF436E
当前希望多选择一个糖果,有几种决策:
- 直接选择,代价是 \(a_x\)。
- 把选了一个的变成两个,代价是 \(b_x-a_x\)。
- 把选了一个的反悔选另一个的两个,代价是 \(b_y-a_x\)。
- 把选了两个的反悔成一个,选另一个两个,代价是 \(b_y+a_x-b_x\)。
对应决策维护即可。维护五个堆,分别是 \(a_x,b_x,-a_x,b_x-a_x,a_x-b_x\)。第一个和第二个都要求没被选过,第三个和第四个要求选过一次,第五个要求选过两次。然后就没啥了,哨兵是个好东西。
CF351B
首先对于第二个人而言,不会出现只有一种操作合法的情况。因为逆序对数量为零的时候就直接结束了,顺序对也会在第一个人的努力之下不为零。所以可以把两个人的一轮看成是一个整体,有一半的概率逆序对减去二,有一半的概率数量不变。奇偶分别讨论一下即可。
CF351E
对于两个点 \(x,y\) 而言,如果 \(|x|>|y|\),那么只要第一个数是正的,那么都会产生一个逆序对,否则肯定会产生一个逆序对。相似地,如果 \(|x|<|y|\),那么第二个数是正的时一定有一个顺序对,否则一定有一个逆序对。得出结论,一对数是否有贡献只取决于绝对值大的那个数是正是负。于是可以对于每个数求出左边和右边比自己绝对值小的数,然后权衡利弊之后决定自己以正数还是负数的形式出现,累加更优贡献即可。
CF598C
用 atan2
函数求出每个向量和 \(x\) 轴非负的转角,然后排序,取相邻的更新即可。
CF551C
不错的二分答案题。有一个显然的贪心策略是后面的箱子用尽量少的人去搬,毕竟每段路走的人越多肯定是更劣的。所以就可以二分答案了,检查的过程就是一个人一个人地去贪心,每个人都是尽量把后面的箱子搬走,然后更新左右端点即可。
CF551D
一道比较简单的题。显然对于每一位分别考虑,定义 \(b_x=a_x|a_{x+1}\),那么最后 \(k\) 的某一位是 \(0\) 等价于 \(\forall i,b_i\) 的对应位都是 \(0\);至于 \(1\) 的情况,用所有情况(即 \(2^n\))减掉即可。然后问题就变成了求前者。一个显然的结论是说原数组不可能出现连续的两个数,用 \(f_{x,0/1}\) 代表前 \(x\) 个数已经填好了,最后一个数对应位是 \(0/1\) 的方案数。显然有 \(f_{x,0}=f_{x-1,0}+f_{x-1,1},f_{x,1}=f_{x-1,0}\),显然答案数列是个斐波那契数列,快速幂优化即可。
CF1C
写这个题更多的是因为情怀。就是先三点求圆,然后求出相邻圆周角的大小,然后求出它们的最大公约数。显然多边形的边数越少(中心角越大),这个多边形面积就越小,所以从小到大枚举边数,如果发现可以的话就直接带入半径去求答案即可。这道题不知道为什么精度要放得比较宽才能过。
CF505C
就是一个很小的点。显然的暴力做法是用 \(f_{x,y}\) 代表到 \(x\) 号节点并且上一步是 \(y\) 的最大价值,但是这显然是很夸张的。然后有一个常用的技巧是如果希望把一个数分解成很多个正数的和,那么不同的正数个数一定是不超过根号的,很好理解。到这道题,由于要求跳跃的距离是连续的,所以可能到达的步数值只有根号个,这样一来状态数就降下来了。
CF414C
一道非常套路的题目。把一个长度为 \(2^k\) 的序列取反等价于先交换两个 \(2^{k-1}\) 的子串,然后每个子串再交换各自 \(2^{k-2}\) 的子串,递归下去。而每次交换都会对逆序对数量产生一个固定的影响值,而且由于题目中要求的是全局交换,所以不需要知道每个段具体的逆序对,只需要知道某一长度贡献的逆序对数量即可。注意说它有重复元素,计算的时候要注意一下。统计和修改方面暴力即可,复杂度 \(O(n2^n)\)。
CF414D
注意某次操作的代价是当前这个节点上的水的数量。一个显然的最优策略是把尽量多的水堵在相同的深度,这样它们就可以在相同的时间到达根。分析题目发现一个费用可以让一份水晚一个时间单位到达,所以只需要尺取法求出固定到达时间的前提下最多能得到的水的数量即可。复杂度线性。
CF444B
一道不错的根号分治题目。题目的大意是有一个随机的排列和一个近似随机的 \(01\) 串,然后求卷积最大值。由于随机,可以想到最大值可能可以一下子更新很多值,所以只需要暴力去更新即可。然而会在 \(1\) 的数量很少的时候会出问题,但是想到这个时候暴力的成本也不会太高,所以根号分治即可。
CF455C
就是一个第一眼没看出来的结论,是说把两棵树连在一起,新树直径最小的方案是把两个直径的中点连接起来。可以用反证法来证,但感性理解也非常简单。
CF455B
一道博弈论的题目。\(k=1\),即两个人只玩一轮的情况是比较简单的,定义 \(f_x\) 代表在 Trie 树上已经填了 \(x\) 对应前缀的字符串的前提下,先手有没有必胜状态,按照一般的方法去做,如果后继中有 \(f\) 值为假的点,那么走到这个点上肯定能获胜;如果后继中没有这样的点,那么显然必败。由此可以拓展到 \(k\ne 1\) 的情况,此时就引出这道题最巧妙的点,一个人可以故意去输。假如一个人同时有必输策略和必胜策略那么他可以一直输,到最后一局的时候出其不意赢下比赛。如果一个人只能赢,那么先手的位置会在两个人之间交替,此时答案就和总局数有关。如果一个人只能输,那么先手权永远是他的,然而他永远也赢不了,所以输麻了。一个人不可能两个策略都不存在。至于必输策略可以有相似的方法去求,只不过边界(也就是叶子)要从返回假修改成返回真。
CF484C
一道比较有用的题。首先每一轮的置换应该是相似的,所以原来到底是些什么字符并不重要,于是问题可以抽象成一个初始为 \(0\dots m\) 的序列变化成另一个序列的过程。由于它的变换窗口是在移动的,所以可以看成是变换窗口不动序列整体向左循环位移一个,比如原序列是 012345
,一次对前四个数变换之后可能是 021345
,左移一次之后可能就变成了 213450
。于是一轮操作就可以如此描述了,会发现这玩意可以倍增,所以可以使用类似快速幂的形式来做,复杂度就降到了 \(O(N^2\log N)\)。
CF484A
一个很简单的东西但是当时人傻了没想出来。只需要从低位到高位贪心即可,如果当前位是 \(0\) 并且变成 \(1\) 之后比 \(r\) 小就把该位变成 \(1\) 即可,复杂度 \(O(T\log S)\)。
CF1626F
如果没有减的操作就很简单,所以想到去找不变量。记 \(K=\text{gcd}(1\dots k)\),那么发现在整个过程中 \(a_i\%K\) 会越来越少,但是 \(a_i/K\) 的值不变。所以可以把这一部分抽离出来,剩下部分的值域一下子就变得很小了,期望就可以直接暴力 DP 去求了。具体而言,用 \(f_{x,y}\) 代表这个数在第 \(y\) 轮操作之前是 \(x\) 的情况下对答案的贡献期望,可以简单地列出方程:\(f_{x,y}=pf_{x,y-1}+(1-p)f_{x-x\ \text{mod}\ y}\)。复杂度 \(O(kK)\)。
CF1418D
显然把点集划分成两个部分,左边的点往左走,右边的点往右走,于是最后的答案就是最右点到最左点的距离减去其中一段的长度,既然希望代价最小于是就只需要动态维护最大的相邻元素差值即可。然后发现一个不重要的性质是重复的点不会影响答案,不论是加入还是删除都是一样的,所以 map 辅助一下就可以用 set 来做了。然后就是答案上用可删堆可以很方便的维护,复杂度显然线性对数。
CF722E
用 \(f_{x,y}\) 表示从原点到关键点 \(x\) 之后恰好经过 \(y\) 个关键点的方案数,于是枚举上一个点是哪个,有:
显然会算重,但发现假如世界上只有三个点 \(a,b,c\),\(a\) 到 \(b\) 再到 \(c\) 的方案数可以看成是从 \(b\) 出发(并且已经经过一个特殊点啦)的方案,在计算 \(f_{c,2}\) 的时候减掉这一部分即可,这玩意貌似有个名字叫做差分容斥。推而广之有方程:
暴力 DP 即可。而且根据值域第二维只需要开到 \(\log s\) 级别,至于那些经过特殊点比较多的路径,可以把起点和终点当成是两个特殊点,这样一来只需要用总方案减去两个特殊点的和多个特殊点的就是剩下的那些情况了,复杂度 \(O(N^2\log S)\)。然后一个要注意的题就是这种路径计算题目预处理的时候要预处理边长的两倍,切记。
CF830D
很不错的一道题。显然用 \(f_x\) 代表 \(x\) 层的答案。考虑这条路径和根的关系,如果交集为空那么答案就是 \(2f_{x-1}\),如果是一个端点的话答案就是 \(4f_{x-1}\)(可以搭在起点或者终点所以要乘二)。如果跨过两个子树答案就是 \(f_{x-1}^2\),但是如果起点和终点在同一个子树就不太好弄了,因为问题相当于求一棵子树内有两段路径的方案数,而要计算路径的方案就要算四段的,这启发我们再加一维,用 \(f_{x,y}\) 代表 \(x\) 层抽离了 \(y\) 条路径的方案数,此时根节点的决策就显得比较简单了,转移即可。然后会发现实际的状态可能非常多,但是事实上用不了那么多,因为我们最后的答案会是 \(f_{m,1}\),而每一层最多能把两个线段合并起来,所以第一层的时候最多有 \(m\) 条线段是有用的,也就是说线段数量大于 \(m\) 的状态是无用的。本来还想保险点搞 \(2m\) 的,但是 CF 的老爷机跑不过去没办法。
CF917D
用 \(f_x\) 代表答案,用 \(g_x\) 代表固定了 \(x\) 条边已经被选择,其它不知道的方案数,根据定义有:
根据二项式反演可以得到:
而根据 \(g_x\) 的定义,可以看成是把图先加上了 \(x\) 条边,也就是生成了 \(n-x\) 个连通块,然后把连通块连成一棵树的方案数,而经典结论(用 prufer 序列来证),\(n\) 个连通块 \(k\) 个连通块使之联通的方案是 \(n^{k-2}\prod\limits_is_i\)。所以只需要求出后面的 \(\prod s_i\) 即可。
可以换一种定义方法,把上面那个式子解释成有 \(k\) 个连通块,每个连通块里选一个点的方案数。然后就可以定义 \(f_{x,r,0/1}\) 为子树 \(x\) 中选了 \(r\) 个连通块并且这个该连通块选没选点的方案。然后可以枚举孩子 \(y\),考虑两个集合是否合并即可。复杂度 \(O(N^2)\)。
CF204D
希望借此题解来总结一下这一类统计问题应当如何做到不重不漏。
这一类题目有共同的特点,即假如单纯的用 \(f_{x,0/1}\) 来表示某个前缀是否符合某个性质时的方案数来进行转移的话会出问题,原因在于这类题描述的合法串可能有多个合法点(合法点是我们判定这个串合法的依据,比如这道题中就是连续出现的黑白段),“多个”体现在这道题里就是一个串中可能有多个黑白段,这样一来就可能被统计多次。
具有这个特性的最著名的题目之一就是 CSP-S2021 的 T2,那道题的难点之一就是普通的写法可能会导致一个串在多个断点处被贡献,从而导致出错。解决那道题的方法之一就是用 \(f_{l,r}\) 来代表区间被一个括号完整包含,而 \(g_{l,r}\) 则没有这个限制并加以区分。分析一下这个解法的思想就是强制命令每个合法串只在第一个合法点被贡献,这样一来就能做到不重不漏了。
说回这道题,根据相同的思路,我们可以令 \(f_x\) 代表这个前缀长度为 \(K\) 的后缀是第一个出现连续白色的方案数,而 \(num_x\) 代表这个前缀出现过连续白色的方案数。相似地,可以令 \(g_x\) 代表这个后缀相应的前缀是第一个出现连续黑色的方案,而 \(num'_{x}\) 是这个后缀出现过连续黑色的方案数,统计答案的时候应该是 \(ans=\sum f_x\times num'_{x+1}\)。这样一来,每个合法串只会在第一次出现合法白段的段尾被贡献,就能做到不重不漏了。
CF1528E
也是一道很不错的计数题。首先考虑转化题目中的限制,前两个似乎都没有什么意思,第三个需要思考一下,发现大概可以分成三种情况:内向树、外向树以及一棵内向树和外向树拼在一起形成的哑铃一样的东西。对三种情况分别讨论,首先是内向树。用 \(f_x\) 代表树内最长路径长度为 \(x\) 时的方案数,考虑它有几个孩子,如果只有一个孩子那么答案就是 \(f_{x-1}\),如果有两个孩子的话需要考虑去重的问题,如果当前两个孩子的长度都是 \(x-1\) 的话,答案应该是 \(\frac{f_{x-1}(f_{x-1}+1)}{2}\),如果只有一个孩子的长度是 \(x-1\) 的话两个孩子的形态一定不同,此时的答案就是 \(f_{x-1}sum_{x-2}\)。最后由于根可以有三个孩子,需要对孩子个数和去重再做一些工作但都比较简单。然后发现内向树和外向树其实是一一对应的,所以只需要用答案乘二减一(因为一条链同时是内向树和外向树)即可。
至于第三种情况,看起来就非常容易算重,所以第一要务是确定贡献点,这里把贡献点设置为第一次分叉的地方。这就需要满足两个条件,一个是上半部分不能是链(链的话最后得到的就是一棵外向树),一个是下面那里必须立即分叉,记立即分叉的答案是 \(g_x\),显然有 \(g_x=f_x-f_{x-1}\)。于是最后的答案就是 \(\sum(f_{x}-1)g_{m-1-x}\),注意取模即可。复杂度线性。
CF1114E
有等差数列。支持单点询问,并且可以询问数列中是否有大于询问数的元素,确定第一项和公差。先通过二分答案确定最大值,然后随机一些询问可以得到集合内一些元素的差值,而这些差值的 \(gcd\) 大概率就是公差。相当于是在 \([1,m]\) 中随机出来一些数,这些数的 \(gcd\) 大概率是 \(1\) 一样的。
CF1088D
\(62\) 次询问想到从高位向低位进行询问,并且每一位可以询问两次。由于之前的位已经确定,那么本次询问可以通过把对应位置赋一的方式清零,那么两个数的大小便取此时枚举到的这一位的大小关系。先给这两个数对应位置取反比较,然后分类讨论:如果当前的大小关系和之前求得的大小关系相同,说明大小关系不由这一位决定,也就是说两个数对应位相同,再用一次询问确定到底是什么数即可;否则说明原来是 \(1\) 的数变成了 \(0\),原来是 \(0\) 的数变成了 \(1\),这就改变了大小关系,那么根据原来的大小关系就可以直观判断每个数当前位的数。同时由于大小关系由这一位决定,后面的大小关系便需要再次计算。综上,会使用不超过 \(61\) 次询问,可以通过题目。
CF1764G3
一道非常好的交互题。
首先明确询问的内容,每次询问的是某个区间对 \(2\) 的答案。因为可以想到,数列中除二相同的数实际上是两两配对的,询问的答案相当于是组数,所以可以结合区间的长度求出区间中落单的数的个数,基本的询问格式应该是对于一个位置 \(p\),分别询问 \([1,p]\) 和 \([p+1,m]\)。当 \(n\) 是奇数的时候可以想到落单的数只会是 \(1\),因为同一组的数在两个询问中都会贡献答案,只有 \(1\) 不会,所以 \(1\) 只会在答案更多的那一边,二分即可。
当 \(n\) 是偶数的时候比较麻烦,因为 \(n\) 也是一个一定落单的数。于是可以在上面的思路上进行一些调整,仍然是询问 \([1,p]\) 和 \([p+1,m]\),如果 \(1\) 和 \(n\) 在同一侧那么表现出来就是那一侧答案更多,正常挪动指针即可;如果在异侧,那么可以使用一次询问来确定 \(m\) 的位置,这样一来就可以在后续的询问中排除掉影响。用这样的策略可以过掉 Medium。要过掉 Hard 还需要优化掉一次询问,考虑最后一步 \(l+1=r\) 时,此时分两种情况。如果之前还没有对于 \(m\) 的询问,说明它还呆在这两个位置中,只需要通过一次询问来看 \(l\) 是不是 \(m\) 即可;否则两个数就会分别是 \(1\) 和另一个可以配对的数。而发现在前面的二分过程中已经询问过了 \([1,r]\) 和 \([1,l-1]\) 的答案,所以可以由这两个数值算出 \([l,r]\) 中未配对的那个数是否和 \([1,l-1]\) 中的数配对,具体表现为两个区间未配对的数量相同。如果是的话就只需要再查询一次 \([1,l]\),看 \(l\) 这个数是不是未配对的那个;否则只需要看一下 \([r,m]\),看 \(r\) 是不是未配对的那个就可以了。注意细节。
CF403D
问题显然可以转化成每次给定两个数 \(n,k\),希望找出 \(k\) 个互不相同的正整数 \(a_i\),满足 \(\sum a_i\le n\)。数和数之间有顺序,输出方案数。
令 \(p\) 是这些数的和,令 \(g_x\) 表示阶乘,令 \(f_{x,y}\) 表示有 \(x\) 个正整数加起来为 \(y\) 的方案数,然而这些数在数轴上可能并不是连续的,也就是说确定了 \(k\) 个数的顺序之后还有 \(n-p\) 个空格,而这些空格会分布在 \(k+1\) 个空格之中。\(n-p+1\) 空位给 \(k\) 挡板允许重复的方案数是 \(\binom{n-p+k}{k}\)。于是就可以求出总的答案数:
兴许可以进一步化简,但由于题目中显然有 \(k>50\) 的部分是没有合法方案是,所以可以直接暴力去做。
关于 \(f\),考虑这一步的决策。有 \(f_{x,y}=f_{x-1,y-x}+f_{x,y-x}\)。然后就可以预处理之后 \(O(1)\) 回答了。
然后就是注意枚举顺序,编译器竟然能检测出我的写法可能导致下标负数。聪明。
CF407C
可以对 \(k=3\) 的情况讨论一下,发现其性质。
原始增加量:
差分多次:
发现只需要对 \(k+1\) 层的 \(l\) 加上一个 \(1\),同时在其它层 \(r+1\) 的位置减去一个组合数(显然可以找规律得到)。由于 \(k\) 的值域很小,所以可以暴力去维护,然后还原出原数组即可。
CF1732C2
一道比较好的题目。
首先有一个结论,如果不限制长度的话,那么把给定的区间选满肯定是更优的。可以假设我们已经有一个异或和是 \(x\) 的数列,加进去一个元素 \(a\),那么这个数列的价值变化量应该就是 \(a+x-(x\oplus a)\)。显然这个东西是非负的,所以最优序列的值是可以直接计算得到的,所以对于 C1 可以考虑枚举左端点,然后二分右端点,找到第一个右端点使得这个区间的答案等于计算的最优答案,更新即可。
而对于 C2 而言就需要更具象化的柿子了。考虑上面那个柿子,显然可以按位考虑,分类讨论之后发现对于某一位而言,当 \(x\) 和 \(a\) 的这一位同时为 \(1\) 时,贡献是这一位的两倍;对于其它情况这一位都是没有贡献的(就拿 \(1,0\) 举例,\(a+x\) 这一位是 \(1\),\(a\oplus x\) 这一位也是,一减就没了)。然后可以推出假如一个序列某一位上 \(1\) 的个数是 \(t\),那么这一位的贡献应该是 \(\lfloor\frac{t}{2}\rfloor\times 2\) 个该位对应的权值(因为只有第偶数次出现才会有贡献,而每次贡献会贡献两个权值,所以有这个柿子)。
于是可以对区间内每一位 \(1\) 的数量分类讨论,如果是偶数的话就很简单,第一个 \(1\) 到最后一个 \(1\) 之内的数都必须选,这显然是最优且唯一的方案。如果是奇数的话,为了缩短长度我们可以去掉第一个或者最后一个 \(1\)。最终选择的区间是这些位对应的决策区间的并。
于是问题就变成了有很多个区间,有些区间必须选,有些区间两两配对需要至少选一个,希望最小化这些区间并的大小。考虑到区间数量是很少的,所以可以枚举答案区间的左端点,然后对于剩下的区间贪心即可。设值域为 \([1,S]\),复杂度即是 \(O(N\log^2S)\)。
CF708E
令某一行某个方向恰好失去 \(i\) 个方块的概率为 \(P_i\),有:
令前 \(x\) 行连通且最后一行是 \([l,r]\) 的概率为 \(f_{x,l,r}\),有:
既然只和 \(t\) 有关,考虑能否把 \(f\) 干掉。于是有:
于是需要维护 \(P\) 的前缀和、\(t_{x}P_{x}\) 的前缀和(虽然很奇怪)。然后就可以 \(O(N^2)\) 转移了。
CF407E
首先判掉 \(d=0\) 的情况。然后原序列可以被拆分成多个极长的、模 \(d\) 余数相同的段,答案只可能在段中产生。还有个区间至多能插入 \(k\) 个数的限制,也就是除以 \(k\) 之后呢最大值和最小值的差不能超过 \(len+k-1\),即: \(\max-\min+l\le k+r\)。符号前面的柿子只和 \(l\) 有关,维护一下即可。也就是说我们希望找到最远的 \(l\) 使值 \(p_l\le k+r\),线段树上维护一个区间最小即可。前面那个部分显然用单调栈来维护,而且由于单调栈相当于是一个左闭右开的节点,所以甚至没有砍区间之类的操作,维护起来就很方便。线段树就是区间加区间最小值。
CF1422F
比较妙的一道题。首先显然是对质数大小进行根号分治,小的质数相当于是希望求区间最大值,可以用ST表进行维护;大的质数由于只可能出现一次,于是问题就转化成了类似HH的项链的形式,多次询问某个区间某个质数是否出现。但由于题目要求强制在线,所以可以用可以持久化线段树来维护这一过程,于是每个线段树就只需要维护区间积和单点修改,都是可持久化线段树的基础操作。至于修改的位置和项链一样记录该位置的质数上一次出现的位置即可。需要卡一下空间。