2022年三月好题收集

收集一些有启发的题目


ABC243F

题意:有一个抽奖,$n$种奖品,每种奖品出现的概率为$w_i$,求$k$次抽奖恰好抽到$m$种不同奖品的概率吗,取模 ($n,m,k\leq 50)$

很容易想到阶段就是目前已经抽的次数和目前抽出的不同礼物数

假设抽到的可重集是$S$。

为了方便计算,我们钦定这个排列的编号是单调递增的,我们只需要求出每种排列,再乘上这种排列的全排列个数。

全排列的个数为

$\frac {k!}{cnt_1!\times cnt_2!\dots \times cnt_m!}$

那么答案就为

$\frac {k!}{cnt_1!\times cnt_2!\dots \times cnt_m!} \times p_1^{cnt_1}\times p_2^{cnt_2} \times \dots \times p_k^{cnt_k} $

发现下边那一坨最后计算不好处理,也不好放进状态里,所以考虑把它的代价放到转移里。

$f(i,j,t)$表示前$j$次抽奖(结果均在$[1,i]$)抽出了$k$ 个礼物的概率除以所有次数的阶乘之积。

然后就有转移$$ f(i,j,k) = f(i-1,j,k) +\sum _{t=1} ^j f(i-1,j-t,k-1) \times p_i^{t} \ / t! $$

答案即$f(n,k,m) \times m!$

将不好计算的代价处理到造成它的步骤上


解法2 :

考虑$f(i,j,k)$直接表示前$i$种奖励,抽了j次,有k个不同的概率。

$f(i,j,k) = f(i-1,j,k) + \sum _{t=1} ^ j f(i-1,j-t,k-1) \times p_i ^t \times \binom{j}{t}$

其中组合数表示在t次中选择j次(类似插板)

考虑按单增的顺序考虑集合


ABC242F

题意:给出一个$n \times m$的棋盘,求在上面放$w$个白车,$b$个黑车,黑白车不能互相攻击的方案数。

$(n,m\leq 50 , w ,b \leq 2500)$

很显然地,每行每列要么只放一种车,要么什么都不放。

枚举哪些行哪些列放黑车,白车,这样黑白车都独立了,

$f(i,j,k)$表示在$i$行,$j$列中放置$k$个车的方案数(其中每行、每列至少放置一个车)。

则$ans = \sum _{i=0} ^{n} \sum_{j=0}^m\sum _{x=0} ^{n-i} \sum_{y=0}^{m-j} f(i,j,w) \times f(x,y,h)$

则$f(i,j,k) = \sum _{x=0} ^{i} \sum_{y=0}^j (-1)^{x+y} \text C_{(i-x) * (j-y)}^k * \text C_i^x * \text C_j^y$ 容斥一下即可(钦定哪些行,列不放)

预处理必要的信息,将子问题独立


CF1648D

题意懒得写。

神仙题 %%%

涉及到区间求和的情况一般都考虑前缀和,又因为只有两次“转弯”,设其位置分别为$i$,$j$

则$ans(i,j)$表示在$i$从1下到2,在$j$从2下到3的答案,可以求出

$ans(i,j) = sum1(1\to i) + sum2(i\to j) + sum3(j\to n) - cost$

$ = sum1(i) + sum2(j) - sum2(i-1) + sum3(n) + sum2(j) - sum3(j-1) + cost$

取出与$i,j$分别有关项

令$f(i) = sum1(i) - sum2(i-1) $ , $g(i) = sum2(j) - sum3(j-1)$

则$ans(i,j) = f(i) + g(j) + sum3(n) - cost(i\to j) (i\leq j)$

不好处理的地方在于走下来,如果没有这个“下来”的过程就比较好处理。

观察接下来将代价拆成两部分:从$(1,1) \to (2,j)$的代价以及之后的代价

因为走下来一定需要一条线段,所以我们考虑从哪一条线段走下来的。

从该线段中一点走下来,要么是从之前的某一条线段的末端点走到这个点的,要么是在该线段内第一行走下来的。

令$dp(j)$表示从$(1,1)\to(2,j)$的最优的$f(i) + cost(i\to j)$。

容易发现在这样的枚举下需要用到的只有线段末尾的$dp$值。

$dp(i) =\max _{r_p = i}\{ \max_{j=l_p-1} ^{r_p-1} \{ dp(j) \} ,\max_{j=l_p} ^{r_p} \{f(j)\}\} $

用一个简单的线段树维护$\min\{dp(i-1) , s(i)\}$即可。

接下来需要求出选择每一个线段走下来的价值。

要么直接从该线段上方的某一个点走下来,要么从之前的某一个满足$r_q\leq l_p$的线段走来,则答案为$\max[i,j\in[l_p r_p] ,i\leq j ]\{\max\{dp(i-1) ,f(i)\} , + g(j) \} - cost$

使用线段树分治维护$x(a) + y(b) (a\leq b) $的板子维护即可。

将代价转化为具体与什么相关


P4657

题意懒求得写。

考虑起点确定的情况

那么选择路径的代价就是所有点的儿子的代价之和

$f(i,j)$表示从根节点向点i走,目前丢了j个磁铁的最大价值

显然地:

$f(i,j) = max\{f(fa , j) , f(fa,j-1) + sum(i) - a(fa) \}$

其中$sum(i)$表示点i周围的点的价值之和。

话说这么智障一个dp+随机化能骗80分/kk

考虑不确定起点的情况

像点分治一样,考虑将一条路径拆成(可以为空的)两部分。

令这条路径上的最高点为$A$

那么拆成$u \to A , A\to v$两部分。

考虑分别计算两部分的代价。

$up(i,j,1/0)$表示从点$i$的子树向上走到$i$的最大价值。

$down(i,j,1/0)$表示从点$i$向下走到$i$的子树的最大价值。

最后一位表示点$i$是否选择。

发现$down$ 不好转移,会算重,于是参考$70$分dp做法,钦定只算儿子的代价,最后再加上父亲的代价。

于是有转移

$up(i,j,1) = max\{(up(son , j-1 , 1 ) , up(son,j-1,0)\} + sum(i) - a(son)$

$down(i,j,1) = max\{(down(son , j-1 , 1 ) , down(son,j-1,0)\} + sum(i) - a(fa)$

计算答案和许多此类dp一样,都是在合并儿子时计算。

$ans = max_{i+j \leq v}\{ans , max\{up(x,i,1) ,up(x,i,0)\} +max\{down(son,j,1),down(son,j,0)\}\}$

$ans = max_{i+j \leq v}\{ans , max\{up(son,i,1) ,up(son,i,0)\} +max\{down(x,j,1) + a(fa) - a(son) ,down(x,j,0)\}\}$

加上$father$是因为$x$本身的代价是没有计算$father$的

减去$son$是因为$up$计算了$x$本身的代价,然而$son$是路径上更靠前的节点,故不能提供代价。

类似题目 : P3565

类似点分治,考虑将路径分为两部分考虑,采取“儿子向父亲合并”的办法统计答案


CF1658D2

题意:已知区间$[l,r]$ , 序列$\{a_i \} = [l,r]$,对所有$a_i$异或上$x$序列变为$\{b_i\}$,给出$\{b_i\} , [ l , r ]$ 求$x$.

$l,r,x< 2^{17} $

妙题

由于是由原序列异或得来的,所以必存在一个$b_i = l \oplus x$ (这个性质似乎可以发扬人类智慧)

那么枚举$x = b_i \oplus l$

考虑对于$x $,如何快速检查。

由于性质$"a \neq b \to a\oplus x\neq b\oplus x"$

所以这些数之间肯定是不同的,所以我们只用考虑$(b_i\oplus x)_{max}$和$(b_i\oplus x)_{min}$是否恰好对应$l,r$即可,因为这样$a_i$对应异或回去恰好是$[l,r]$中的每一个数。

使用Trie即可。

人类智慧法:

由于前面的性质,必然存在一个$b_i = l\oplus x, l+1\oplus x , \dots r\oplus x$

所以$x$必然是某个$b_i \oplus [l,r]$

直接随机取10个$[l,r]$个数,将他们对$\{b_i\}$的异或取交集后 $\text{brute force}$即可。


P5760

题意: 维护序列 , 支持以下操作 :

    1.区间加上一个数
    2.查询区间异或和的后m位(二进制下)

$n,q\leq 10^5 ,m\leq 10$

首先异或和加之间是没有直接性质的(考虑过每一位开一棵线段树,发现不行,因为进位) ,所以难以使用普通的ds维护,因为知道区间异或时整体加是不能 $O(1)$ 地求出的。

对于普通的ds难以维护的题目,考虑分块,却发现分块也卡在了整体打tag的一步上,即无法整体 $O(1)$ 地维护区间异或和随加法的改变量。

由于查询是异或的后10位,于是我们大可不必考虑前面的位,即操作是在模 $2^m$ 的意义下进行的 。

那么此时模意义下数的种类就只有 $2^{10} = 1024$ 种了。

基于元素考虑不现实,考虑基于统计的算法。

有与异或偶数次等于没有异或,所以本质就是查询出现的奇偶性。

加法导致无法按位考虑,所以直接的想法是暴力开1024个桶,统计每个数出现的奇偶性。

然后加就是将桶“旋转”,如下:

假设在模意义下 $+x$ 。

原本在 $0$ 的值会到达 $x$ ,$k$ 会到达 $(k + x) \mod n$ 。

(我甚至去想了splay)

然后发现由于奇偶性是 bool 的,于是直接使用 bitset<1024> 维护!

具体做法就是开一棵线段树,每一个点存一个 bitset

区间加时若整个区间被包含,则直接打标记,更改这个点的 bitset 的值,使用位运算优化后 “旋转操作如下” :

s = ( (s << d) | (s >> 1024 - d) ) ;

bitset 左移、右移 多出的位会自动补0 , 很好理解。

区间查询相同,在线段树上把大区间分成很多个小区间,将代表着这些区间的 bitset 异或起来即可得到整个区间出现次数的奇偶性,遍历该 bitset 即可。

时间复杂度 :

$O((n+q) \log n \times \frac a w + q a)$

其中 $ a = 1024$ 。

前半部分是线段树的复杂度计算方式本身复杂度乘上 push_up/down 的复杂度即可。

后半部分是遍历 bitset 的复杂度。

代码较长,放在此处比较占版面,放出关键代码 (线段树) 。

跑的比指令集慢多了


CF1658F

题意: 有一个长为 $n$ 的01序列, 取$k$个子段 , 使得其长度和为 $m$ ,且这些子段的 0总数/1总数 = 原串的 0总数/1总数 。

构造方案使得$k_{min}$ 或输出无解。

神仙题,正常人绝对不会往这个方向想。

首先先判无解,当0,1的数量整除 化简后的 $n/m$ 时一定是有解的,因为只选单个的0、1是可行的。

只用考虑1的个数正确( $= one / n * m$ )即可。

考虑当$n = km$ 时 , 一定有解$k = 1$

证明:

$1\degree $ $k = 1$ 原串即为答案

$2\degree $ $k > 1$

令从i开头长度为m的串的1的个数为$c_i$,即需要找到$c_x = cnt$

那么一定存在$p_1$使得$c_{p_1}\leq cnt$,也存在$p2$ 使得 $c_{p_2}\leq cnt$。

证明是反证,若不存在,则$c_1 + c_{m+1} + \dots c_{n-m+1} <n$

矛盾。

因为$|c_x - c_{x+1}|\leq1$

又因介值定理,一定存在一个$x$使得$c_x = cnt$

当$ n \neq km$ 时,再循环意义下重复刚刚的证明2,即将原串复制若干遍,同样存在$p_1$使得$c_{p_1}\leq cnt$,也存在$p2$ 使得 $c_{p_2}\leq cnt$。

由于现在在循环意义下,所以 $k = 1$ 或 $2$ , 因为有可能是从某个串开头取一段,结尾取一段。


posted @ 2022-03-17 20:25  寂静的海底  阅读(15)  评论(0)    收藏  举报  来源