$Div.1$
A p-binary
考虑从小到大枚举答案 $k$ ,则需要满足
$$
n-k\cdot p=\sum_{i=1}^{k} 2^{b_i}
$$
其中每个 $b_i$ 表示选择了数字 $2^{b_i}+p$.
判断这个 $k$ 是否有解,只需要判断 $popcount(n-kp)\le k$ 是否成立.
若 $n-kp$ 二进制下的 $1$ 的个数比 $k$ 大,则这个 $k$ 无解.
否则,当 $n-kp$ 二进制下的 $1$ 的个数 $\le k$ 时,总可以把 $2^i$ 拆成 $2^{i-1}+2^{i-1}$ ,而凑够 $k$ 个数,即找到一组解.
当 $n\le kp$ 时,就可以退出了,若此时仍未找到解,则一定无解.
1 | //%std |
B Power Products
把每个数质因数分解,得到
$$
x=\prod p_i^{b_i}
$$
这个指数 $b_i$ 可以对 $k$ 取模.
那么对于一个 $a_j$ 来说,找到的 $a_i$ 需要满足,对于每个质因子 $p_i$ ,两者的指数相加在模 $k$ 意义下为 $0$ .
用 $hash$ 去压缩每个数的每个质因子的次数.
在 CF 上写 hash 一定要写双进制模数啊.
1 | //%std |
C Rock Is Push
从那几张样例解释的 GIF 图中大概就能看出做法了.
每次进行 $dp$ 转移时考虑连续移动一段,直到改变移动方向.
设 $f(i,j,k=0/1)$ 表示从 $(1,1)$ 出发,走到 $(i,j)$ ,且当前应该向 右/下 走的方案数.
由于每次移动之后都会切换方向,所以 一行/一列 只会被走一次,那么每次移动之间就不会互相影响了.
当 $k=0$ 时,往右边走,若 $(i,j+1)\sim (i,m)$ 这些位置共有 $x$ 个空位,那么往右最多可以走 $t$ 步.
当 $k=1$ 时,往下面走,若 $(i+1,j)\sim (n,j)$ 这些位置共有 $y$ 个空位,那么往下最多可以走 $t$ 步.
转移需要优化,如果直接上二维树状数组,时间复杂度是 $O(n^2\log^2 n)$ 的,不是很优.
可以利用前缀和的方式进行优化.
计算 $f(i,j,1)$ 时,考虑在 $f(i,j-1,1)$ 的基础上,减掉那些恰好只能到达 $j-1$ 这个位置的贡献,这可以用桶存起来.
如果合法,还需要加上 $f(i,j-1,0)$ 对 $f(i,j,1)$ 的贡献.
计算 $f(i,j,0)$ 同理.
时间复杂度 $O(n^2)$ .
特判 $n=m=1$ 的情况,否则因为根本上没有移动,导致 $f(1,1,0)$ 和 $f(1,1,1)$ 都被算入答案了.
1 | //%std |
D Tree Factory
考虑倒着来实现这个过程,即从给出的树开始,不断操作,用最少的操作次数将它变成一条链.
若一个节点 $u$ 有 $v,w$ 两个儿子,则操作一次可以将子树 $v$ 接在子树 $w$ 下面.
不难发现,每次选择可操作的子树中,最大深度最大的那一颗,将它接在其他子树下面,会使最大深度 $+1$ .
而当最大深度 $=n-1$ 时,就成了一条链了.
那么总操作次数一定是 $n-1-maxdep$ ,其中 $maxdep$ 表示初始时树中节点最大的深度.
对操作过程进行模拟即可.
1 | //%std |