2021.2 做题记录 part.2
P7073 [CSP-J2020] 表达式
绿题不会简直丢人
考虑建立出一棵表达式树
考虑一个操作,如果是 1|x
或者 0&x
,那么结果和 x
无关
所以答案不会变
相应的,如果是 1&x
或者 0|x
的时候,在 x
取反的时候,结果也要取反
所以我们建表达式树的时候把相应不会变的节点标出来
节点里的子树也都不会变
P7324 [WC2021] 表达式求值
发现表达式树求表达式的方法比栈好写不知道多少。。。
首先这题要想到的一个东西是对于这种最大最小值的问题
我们是可以二分的。。。
我们二分一个 \(x\),把所有 \(\leq x\) 的变成 1,其他的变成 0
然后再求一下值,如果答案为 1,那么 \(ans\geq x\)
对应到这道题上
我们发现虽然 \(n\) 非常大,但是对于每一位来说,他的 01 序列都只有 \(2^m\) 种不同的可能。
所以我们可以把这 \(2^m\) 种情况都暴力的求出来
考虑 ?
的处理,我们可以不求值,而是每个点维护 \(p[0],p[1]\) 表示答案为 0 和答案为 1 的次数
最后的答案就是 值\(\times\)出现次数
然后我们对于每一列的数排序一下,查询一下答案
恰好为 \(x\) 的次数即 \(\geq x\) 的减去 \(\geq x+1\) 的
复杂度为 \(\mathcal O(2^m|E|+nm^2)\)
实际上带了一个 4 的常数
所以需要吸氧才能跑过去
不过反正这道题本身就给开了只是洛谷没默认开(
AT3957 [AGC023F] 01 on Tree
考虑贪心,显然第一步要把所有能选的 \(0\) 都选了
然后发现不太好搞。
我们考虑两个 01 串的合并
如果 \(x\) 可以放在 \(y\) 的前面,说明
也就是说,对于全局的 \(\dfrac{one[x]}{zero[x]}\) 最小的 \(x\),他肯定需要跟着他父亲选
所以我们每次把全局最小的和他的父亲合并起来
用并查集维护,直到不能再维护
维护最小值因为有删除,写 deletable-heap
莫名其妙写挂了
所以就用了个 set
\(\mathcal O(n\log n\alpha(n))\)
P4284 [SHOI2014]概率充电器
发现考虑充电成功的概率不太好考虑
考虑反过来考虑充电不成功的概率
那么显然有
发现这个东西是存在互相约束的
但是高斯消元显然复杂度不太对
发现题目中给出的是一棵树
所以我们考虑换根 dp
我们先处理出 \(p(x)\) 表示只考虑 \(x\) 的子树的概率
考虑转移的过程中可能存在的问题
当我们需要求 \(p(x)\) 的时候,相当于此时 \(x\) 一定不选,那么这个时候从他的子节点过来的 \(y\) 就不会和 \(x\) 牵扯上贡献
所以可以直接转移
然后换根的时候,用 \(f(x)\) 表示 \(x\) 不充电的概率设 \(x\) 的父节点为 \(y\),那么有转移
这样转移同样是对的
因为当我们钦定 \(x\) 不选的时候,\(y\) 的答案就不应该有从 \(x\) 过来的部分
\(\mathcal O(n)\)
P1232 [NOI2013] 树的计数
首先考虑把 BFS 序变成 \(1,2,3\cdots,n\)
这样有什么好处呢?
我们发现 BFS 序每一层是连续的,所以问题就转化成了给 BFS 序设置断点
无非就是三种情况
\(i,i+1\) 之间必须断,必须不断,有可能断有可能不断
这三种情况对答案的贡献分别是 \(1,0,0.5\)
最后把所有情况加起来即可
考虑这三种情况分别会在什么时候出现
设 \(y=x+1\),也就是 \(bfn[y]=bfn[x]+1\)
如果 \(dfn[x]<dfn[y]\)
那么 \(y\) 可以作为 \(x\) 的子树,也可以作为 \(x\) 的兄弟,贡献应该为 \(0.5\)
如果 \(dfn[x]>dfn[y]\)
那么这个时候 \(y\) 一定在 \(x\) 的下一层,贡献为 \(1\)
但是这样做会有不完备的地方
考虑 DFS 序的影响
设 \(dfn[y]=dfn[x]+1\),即 \(x,y\) 为 DFS 序上连续的两个数
那么这个时候再进行讨论
如果 \(x+1>y\),这个时候 \(x\) 一定比 \(y\) 靠后出现,但是深度差不一定,所以对答案无所谓
如果 \(x+1=y\),这个时候 \(x\) 可以是 \(y\) 的父亲也可以是兄弟,无影响
如果 \(x+1<y\),这个时候 \(y\) 一定是 \(x\) 的一个儿子,也就是说在 \([x,y)\) 这一部分的 BFS 序上只能找到一个断点
显然这个区间上一定有一个 \(1\),否则不能保证这一点
所以这个区间我们打上标记,这里面的所有 \(0.5\) 都应该是 \(0\)
最后统计一下答案即可
关于这个做法的充分性的证明不会(
感性理解吧
非常恶心的思维题
\(\mathcal O(n)\)
code
CF494B Obsessive String
其实挺简单的脑抽了没想到。。。记录一下
用 \(f[i]\) 表示当前的串选在 \(i\) 的方案数
那么 \(i\) 这个选出来的串的左端点一定要在 \(i\) 最近的匹配的串的左端点的左边
考虑枚举这个 \(j\),转移过来的方案数是一个前缀和的形式
所以我们求前缀和的前缀和就可以 \(\mathcal O(1)\) 转移了
\(\mathcal O(n)\)
CF427D Match & Catch
首先有线性的广义 SAM 的做法
考虑枚举 \(s1\) 的后缀
接下来问题就转化成了判断这个后缀的前缀在两个串里的出现次数
我们把这几个串拼在一起,做一个 dp 即可,转移方程为 \(f[nxt[i]]+=f[i]\)
\(\mathcal O(n^2)\)
P7114 [NOIP2020] 字符串匹配
考虑枚举 \(AB\) 的长度 \(i\)
接下来一个问题是 \(AB\) 会循环几次
我们考虑 \(exkmp\),求出每个位置的 \(z\)
那么长度为 \(i\) 的串重复的次数为
正确性比较显然
发现这样做计算贡献仍然是 \(\mathcal O(n\ln n)\) 的,不太好搞
我们在每次枚举 \(AB\) 长度的时候统一计算贡献
考虑 \(S=(AB)^kC\)
那么我们发现所有 \(k\) 为奇数的时候 \(f(C)\) 都是相同的
同样 \(k\) 为偶数的时候 \(f(C)\) 也都是相同的
所以可以分组计算贡献
用一个树状数组维护即可
\(\mathcal O(n\log|\Sigma|)\)
code
AGC047C Product Modulo
一上来似乎感觉非常好搞
但是这个模数非常恶心
考虑枚举最后是 \(i\) 的有多少个
发现并不好计算
考虑把乘法变成加法,这样我们就可以 FFT 了
但是显然不能取对数
不妨设 \(g[i]=2^i \bmod p\)
那么显然 \(g[i]\) 是互不相同的
这个时候我们的第 \(x\) 位和第 \(y\) 位乘上的结果就到了 \(x+y\) 位了
这样我们 FFT 搞一下就好了
\(\mathcal O(p\log p)\)