AtCoder AGC047 总结
A
由于小数位最多九位,我们先乘 \(10^9\),转化为求 \(10^{18}\mid a_ia_j\) 的个数。
考虑分解质因数,要求 \(2,5\) 的次数都至少为 \(18\) 即可。时间 \(18^2\times n\)。
B
一个串可以变成的串形如,选一个字符,再选一个后缀拼起来。
对反串建 Trie,只需求子树内包含某个字符的串有多少个。
复杂度 \(O(\sum s_i\times 字符集大小)\)。
C
由于 \(P\) 给定且是质数,考虑其原根(原根为 \(2\)),将 \(a_i\) 表示为 \(a_i=2^{x_i}\)。
乘法转化为指数相加,枚举 \(a_i\times a_j=2^{k}\),我们现在要求 \(\sum [x_i+x_j=k]\),FFT 即可。
D
相当于两棵树上的 dist 相乘。套路地,考虑对一棵树点分治,另一棵树建虚树。
在本题里由于是二叉树,所以实际上是枚举一棵树上的 LCA,建虚树叶可以不用建,暴力跳父亲即可。
复杂度 \(O(n\log ^2n)\)。
E
首先 \(A,B\le 10\) 的情况,相当于枚举 \(i,j\) 计算 \([i\le A\land j\le B]\) 的和。\(A_3<A_{0}+A_{1}\) 即可得到 \(1\)。而那个表达式等价于 \(1<[j\le A]+[j\le B]\)。
正解考虑拆分二进制位,那么对于 \(A_0\) 的第 \(i\) 位和 \(A_1\) 的第 \(j\) 位,若都为 \(1\),则贡献 \(2^{i+j}\)。处理 \(2\) 的幂与位移是容易的,而前面的条件同上可以转化为 \((1<A_0[i]+A_1[j])^{i+j}\)。
考虑怎么拆分二进制位,可以从大到小枚举位,若 \(x\ge 2^i\) 则将 \(x\gets x-2^i\),这样可以得到所有二进制位。
考虑怎么减法,对于 \(x-y\),考虑从大到小枚举位,若 \(x\le y+2^i\) 则差中存在 \(2^i\),并令 \(y\gets y+2^i\)。
实现时,可以实现若干个函数,传入运算数下标,返回结果的新下标。
F
\(O(n^2)\)
答案的贡献是相邻点的曼哈顿距离减去【点数减一】。
能到达的点在 \(x\) 和 \(y\) 上都是一段区间。那么排序后可以设 \(O(n^2)\) 的 DP:\(f_{l,r,0/1}\),\(0/1\) 表示当前在区间左端点还是右端点。转移时需要看 \(\mid y_{l-1}-\max/min \{y_{l\dots r}\} \mid\) 是否等于 \(1\),这里 \(y\) 为离散化后的值。
\(y_i=i\)
答案为 \(dis(1,n)+\min(dis(1,i),dis(i,n))\)。
正解
\(y_i=i\) 的情况启发我们,对于 \(|y_i-y_{i+1}|=1\) 的连续段可以一起转移。此时合法的区间只有 \(O(n)\) 个。
这是因为如下图给连续段分层,那么在同一个极大矩形中,合法的区间的左右端点一定在同一层或者相同层里,而层数是 \(O(n)\),因此合法区间数是 \(O(n)\) 的。而对于一个连续段同时处于多个极大矩形里的情况,发现它只会存在于最多两个极大矩形。
用 std::map
保存状态可以做到 \(O(n\log n)\)。