杂题选做1

每篇写十个题吧。写没有整场板刷或者有价值的。

题目按分数排序。链接是提交记录。

这篇全是CF。

CF1737D

*2200

有意思,但不多。

注意到可以构造自环。

考虑枚举每一条边,用它直接联通 \(1,n\),那么不难发现,一种方案:设边 \((u,v)\)\(ans=val_{(u,v)}\times \min(dis(u,1)+dis(v,n)+1,dis(v,1)+dis(u,1)+1)\)

这样会少一种样例3中的情况,即一个端点经过另一个端点到达 \(1,n\)

那么你可以通过自环,枚举一个点,然后设较近的那个端点到这个点的距离是 \(dist\),则答案是 \(val_{(u,v)}\times (dist+1+dis(k,1)+dis(k,n)+1)\)。其中第一个 1 是变成自环,第二个 1 是最后变成 \((1,n)\) 之后走一次。

CF1743F

*2300

题意:有 \(n\) 个区间 \([l_i, r_i]\),三种运算,与,或,集合异或,求顺序在 \(n\) 个集合中的 \(n-1\) 个空位插入运算(从左往右做),最后能得到的集合大小之和(所有插入情况的和)。

不难。简单的想法是设 \(a_{i,j},b_{i,j}\) 分别是 \(i\) 这个位置在第 \(j\) 个集合运算之后在集合中存在/不存在的方案数,则转移显然,并且是矩阵形式,可以直接写棵线段树维护。维护时只需维护当前的 \(a_i,b_i\) 而不用维护 \(j\)

这种做法无脑,但是常数比较大,矩阵乘法经过略微卡常可以通过。

另一种做法是扫描线区间,从左往右考虑每一个位置的贡献,对于一个区间显然只有包含和不包含这个位置两种状态,你进入一个区间时加入,出一个区间时恢复即可。还是用线段树维护矩阵,但是这个不用维护标记,只要维护区间矩阵乘积即可。

转移矩阵两种做法都一样。

复杂度都是 \(O(8\times n \log n)\)

CF1718C

题意:有序列 \(a_{0}...a_{n-1}\) 从一个位置 \(i\) 开始跳 \(n\) 步,每步从 \(j\rightarrow (j+k-1)\% n\),将经过的所有点点权可重复计算之和作为权值,\(q\) 次单点修改,每次修改完查询最大权值。\(n,q\le 2\times 10^5,1\le a_i\le 10^9\)

经典转化成枚举一个 \(n\) 的因数 \(p\),从序列中 \(q < p\) 开始,求序列中 \(p\times \sum_{0\le j < \frac{n}{p},l=q+j\times p} a_l\) 的最大值。

\(m=\frac{n}{p}\),则不难发现当 \(m\) 是质数的时候一定会取到一个最优答案。证明显然。

然后发现 \(n\) 的不同的质因数个数最多只有 7 个,可以对于每一个质因数暴力维护所有起始位置 \(q\) 对应的权值。

用对顶堆即可。

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

CF1743E

*2400

题意:有两种攻击武器,冷却时间 \(t_1, t_2\) 和威力 \(p_1, p_2\) 分别给出(初始需要冷却),有一艘敌舰,有耐久 \(h\) 和防御 \(s\),一次攻击对耐久造成的伤害是总威力减防御(两个一起发射的总威力是威力和,否则就是单个威力)。

\(p_1,p_2,h,s\le 5000\)\(t_1,t_2\le 10^{12},p_1,p_2>s\)

求最少经过多少时间可以把他耐久清空(冷却好可以等待一段时间发射)。

不很难。

考虑设 \(f_i\) 表示造成了 \(i\) 耐久的伤害,同时两种武器刚刚发射完的最短时间。

枚举转移时间 \(t\),其中 \(t\) 必然是 \(t_1\)\(t_2\) 的倍数,因为你要么两个武器一冷却就攻击一直到他死,不等另一个武器,要么一个武器会等一次另一把武器(然后变成两个武器刚刚攻击完的状态,可以在下一次转移中考虑而不必在本次考虑),而等一次这个过程中显然不去等的那把武器会一直攻击。于是两种状态下都是其中一个的倍数,于是可以枚举时间倍数然后转移(转移的话你钦定前面的随便打,最后一次等即可)。而第一种情况显然也能通过这种转移得出(显然等的那把最后一次攻击完剩一段空余没用,不如和另一把一起等,显然不劣)。

于是做完了。复杂度 \(O(h^2)\)

CF1737E

*2500

感觉比上一个题顺多了。可能因为比较OI风格。

题意:木棍上有 \(n\) 个相互距离相同的食人族,从左往右排,初始实力都是1,他们以相等的概率向左或右走(所有人和方向速度一样),两个食人族相遇时,更有实力的那个会把菜的人吃掉,实力加上菜的人的实力,如果实力相同,向左走的吃掉向右走的。求每个人最后存活的概率,分数取模。一个人走到最左或最右时,会立刻掉头。

因为求概率,不妨转化成方案数,最后除掉 \(2^n\) 即可。

考虑除了最后一个人,其他人必然向左走才能不被第一时间干掉,于是我们可以考虑向左走的时候,他先要干掉左边所有人才能回头吃剩下的人,那么他显然首先可以吃掉左边连续的一段向右走的人,然后更右的人会合并成一个人来和他互吃,那么设这个人是第 \(i\) 个人,则他左边至少要有 \(\lceil \frac{i}{2}\rceil-1\) 连续向右走的人才能把前面都吃掉,这个比较好处理。你钦定第 \(j\) 个人是 \(i\) 左边第一个向左的,则这种情况的答案显然是 \(2^{j-1}\)

于是这部分总答案是 \(g_i=(\sum_{1\le j\le i,j\le i-j}2^{j-1})+1\),最后那个1是左边全是向右的情况。

然后考虑向右吃,设 \(f_i\) 表示目前吃到大小是 \(i\),最后吃到 \(n\) 的方案数,然后你枚举 \(j\),钦定 \(j\)\(i\) 后面第一个向左走的人,那么当 \(j-i<i\) 时,可以 \(f_i\leftarrow f_i+f_j\)。因为 \(n\) 自带方案数乘2(左右都等价于向左),初始化设 \(f_n=2\) 即可。

\(i\) 个人的答案就是 \(\frac{g_i\times f_i}{2^n}\)

CF1736E

*2600

题意:每一轮可以先进行操作,交换任意两个相邻数然后将其中一个变为0,或者不做操作,然后第 \(i\) 轮操作结束后答案会累加上 \(a_i\)(不是交换的那个数)。求最大答案。

\(n\le 500,a_i\le 10^6\)

感觉不难,但是有点怪。

一个naive且简单的想法是设 \(f_{i,j,0/1}\) 表示进行完 \(i\) 轮操作,当前用第 \(j\) 个数交换过来当答案,第 \(j\) 个数在 \(i\) 这个位置还是后面一个位置,枚举下一个选什么,能够直接转移。但是不好写。

可以设 \(dp_{i,j,k}\) 表示 \(i\) 轮操作后,目前这个位置使用第 \(j\) 个数来更新答案,当前用了 \(k\) 次操作。

转移,要么 \(dp_{i,j,k}\leftarrow dp_{i-1,j,k-1}+a_j\),要么 \(dp_{i,j,k}\leftarrow dp_{m,n,k-(j-i)}+a_j,n < j,m<i\)

不难发现后面的一坨可以维护前缀最大值。复杂度 \(O(n^3)\)。但是还是感觉很怪啊。

CF1740F

*2600

赛后补的题。是转化dp题,挺妙的,感觉具有启发性。

题意:有序列 \(a_i\),每个数自己一个集合(初始大小是1),一次可以合并两个交为空的集合,最后剩余的所有集合的大小构成一个可重集,求能得到多少不同的可重集。\(n,a_i\le 2000\)

转化:首先显然按每个数的出现次数考虑。具体的,每一种数出现次数是 \(cnt_i\),必须每个数都分到一个不同的集合中。于是不妨设最后可重集里面的集合大小是 \(w_1,...,w_k,sum_j=\sum_{i=1}^j w_i\),则若对于任意 \(1\le j\le n\) 满足 \(sum_j\le \sum_{i=1}^n \min(cnt_i,j),sum_k=n\) 即能构造出合法的这样的可重集。证明显然。

于是考虑根据这个转化来做,首先为了防止算重,经典的做法是钦定 \(w_i\) 单调,这里不妨钦定 \(w_{i+1}\le w_i\)。那么可以设 \(f_{i,j,k}\) 表示当前考虑到 \(w_i,sum_i=j,w_i=k\) 的方案数,则有转移 \(f_{i+1,j+x,x}\leftarrow f_{i,j,k},x\le k\)

直接做空间时间都不能接受,但是发现 \(i\times k \le n\),也即对于 \(i\),有用的 \(k\) 只有 \(\frac{n}{i}\) 个,总的空间和时间复杂度都变为了 \(\sum_{i=1}^n \frac{n}{i}=O(n \ln n)\)

然后利用后缀和优化一下即可。

复杂度 \(O(n^2 \ln n)\)

CF1746F

*2800

题意:给定序列,要求支持单点修改,查询区间中所有数的出现次数是否都是 \(k\) 的倍数。对于每个查询 \(k\) 给定。\(n,q\le 3\times 10^5,a_i,x\le10^9\)

如果当正经题,不太好做。反正我想了一车各种经典算法,除了莫队都不能做。但是莫队复杂度不对。

你考虑先离散化,然后对于每一种权值随机一个哈希值,然后显然如果区间出现次数都是 \(k\) 的倍数,那么区间中所有哈希值之和必然是 \(k\) 的倍数。发现在完全随机,最劣情况下,大概有 \(\frac{1}{2}\) 的概率错一个查询。所以你对于一个权值随机五十个哈希值,每个都要满足才合法,正确率就保证了。用树状数组维护前缀和即可。

CF1635F

*2800

题意:给定序列 \(x_i,w_i\),其中 \(x\) 单增,\(f(i,j)\) 的权值是 \((w_i+w_j)\times |x_i-x_j|\),每次询问区间 \([l,r]\),要求 \(\min_{l\le i < j\le r} f(i,j)\)

\(n,q\le 3\times 10^5\)

观察性质,我们对于一个位置 \(i\) 只考虑所有 \(w_j \le w_i\) 的位置 \(j\)\(f(i,j)\),那么可以发现我们取每个 \(i\) 左右最近一个这样的 \(j\) 求出答案,对于所有 \(i\) 的答案取 \(min\) 即可。为什么?有一个类似于三角形的关系,设有 \(k < j < i,w_k,w_j\le w_i\),其中 \(f(i,j)>f(i,k)\),那么不难发现这时 \(j,k\) 也在查询区间中,直接取 \(f(j,k)\) 显然更优。所有可以这么做。

然后你单调栈二分求出这样的位置,再扫描线,维护线段树就做完了。

其实只要猜测到左右最近这个性质就并不难了。但是需要灵感。

CF1523H

*3500

题意:给定序列,最多删 \(k\) 个点,每个点可以跳到它后面 \([i+1,i+a[i]]\) 的点,\(q\) 次询问从 \(l\) 点最少几步能跳到 \(t\)。询问独立。

考虑倍增。设 \(f_{i, j, k}\) 表示从 \(i\) 出发,跳最多 \(2^j\) 步,删最多 \(k\) 个点,最远能跳到哪里,则容易看出转移:

\[f_{i,j+1,k1+k2}=\max_{l=i}^{f_{i,j,k1}} f_{l, j,k2} \]

然后中间的取 max 你可以上个 st 表或者 ds 什么的优化一下。

最后考虑类似倍增LCA的方法,从大到小找到差一步到 \(t\) 的步数。你设一下 \(ans_{i,j,k}\) 表示你考虑第 \(i\) 个询问起始点出发,现在考虑到 \(2^j\) 的步数,删除 \(k\) 个点最远能到哪里。注意再记一下每个状态现在跳了几步。

转移大概是

\[ans_{i,j,k1+k2} = \max_{s=l_{i}}^{ans_{i,j+1,k1}} f_{s,j,k2} \]

也需要稍微 ds 维护一下。同时注意到只需要维护 \(ans_{i,k}\) 即可,中间那维可以继承。

具体实现有一些不同寻常,对着AC代码写的,看代码。

本题卡常,注意维度要寻址连续(将与 \(n,q\) 有关的放到最后一维)。

posted @ 2022-10-27 16:07  infinities  阅读(56)  评论(0编辑  收藏  举报