EZOJ 刷题笔记(1)
EZOJ65 A
AC code
当 $p_i=i$ 时强制让 $p_i$ 与 $p_{i+1}$ 交换,这样交换显然是对的并且是最优的。
注意当 $i=n$ 时也要这么做因为你可以找到一个 $p_i (1\leq i<n)$ 与 $p_n$ 交换。
时间复杂度为 $O(n)$。
EZOJ20 ymh喜欢函数
AC code
二分神题,最优选择的答案一定是一个下凸函数,所以先特判掉 $t=0$ 的情况是否可行,然后再二分求 $t$ 即可。
若 $t=0$ 时答案小于 $S$,则函数单调下降的部分小于 $S$,二分的区间一定会缩小到函数单调上升的部分,故二分是正确的。
注意出题人卡了 $\log^2$ 做法,找前 $k$ 大时不能用 sort 要用 nth_element,注意 $\sum_i k_it+b_i$ 可能会爆 long long。
这道题实际上数据保证了 $t$ 在 $[0,10^9]$ 范围内必定有解但是并没有说……
时间复杂度为 $O(n\log{V})$。
EZOJ22 ymh的序列
咕咕咕~
EZOJ45 SKY_magician的完全图
AC code
设 $f_{i,j}$ 表示 $i$ 个点的完全图划分成 $j$ 个连通块的方案数,$g_i$ 表示 $i$ 个点的完全图删若干条边的方案数,则有:
$f_{i,j}=\sum\limits_{k=1}^{i-1}\dbinom{i-1}{k-1}\times f_{k,1}\times f_{i-k,j-1} (j\geq 2)$
$g_i=2^{\frac{i\times (i-1)}{2}}$
$f_{i,1}=g_i-\sum\limits_{j=1}^{i-1}\dbinom{i-1}{j-1}\times f_{j,1}\times g_{i-j}$
上述状态转移方程并不难理解,提示:为防止重复计算方案,选取一个关键点,并选择其他一些点连向该关键点构成一个连通块。
最终的答案即为 $f_{n,m}$,注意到题目要求至少删一条边,所以 $m=1$ 时要将一条边都不删的情况给减去。
时间复杂度为 $O(n^3)$。
EZOJ50 SKY_magician的集合
AC code1
AC code2
注意到 $a_i$ 最大才只有 $10^6$ 也就是说枚举因子 $O(V\log V)$ 是能过的。
设集合中有 $cnt_i$ 个数是 $i$ 的倍数,则答案很显然是 $\sum_i [\forall j\neq i\land i\mid j, cnt_i\neq cnt_j]$。
因为只要存在一个不满足该条件的 $j$,则 $j$ 就可能成为某几对数的最大公因数,$i$ 就一点都不可能了。
AC code1 是我一开始写比较暴力的 $O(n\log{n}+n\sqrt{V}+V\log{V})$,但是由于 $n$ 和 $V$ 比较小就冲过去了。
AC code2 是此题的正解,时间复杂度为 $O(n+V\log{V})$。
EZOJ127 SKY_magician的qwq
AC code1
AC code2
把 w 看成 $0$,把 q 看成 $1$,问题等价于求长度为 $n$ 的 01 序列满足任意两个 $1$ 中间至少有 $k$ 个 $0$ 的个数。
这个问题就很简单了,可以考虑 DP 也可以考虑组合数去计算。
设 $f_i$ 表示考虑前 $i$ 位且第 $i$ 位是 $1$ 的合法 01 序列方案数,则有:
$f_i=1(0\leq i\leq k)$
$f_i=\sum\limits_{j=0}^{i-k-1}f_j$
上面的那个 $\sum$ 显然可以记录前缀和来优化掉,AC code1 是这种做法,时间复杂度为 $O(n)$。
或者我们也可以把它看成组合数问题,至少有 $k$ 个 $0$ 在两个 $1$ 中间,那么就可以把这些 $0$ 都删去。
所以我们可以枚举有 $i$ 个 $1$,原问题就相当于在 $n-(i-1)k$ 个位置里面放 $i$ 个 $1$ 的方案数,即为:
$\sum\limits_{i=0}^{m}\dbinom{n-ik+k}{i}$,其中 $m=\lfloor\dfrac{n+k}{k+1}\rfloor$ 表示 $i$ 的上界(由 $n-(i-1)k-i\geq 0$ 推导得到)。
注意模数 $5000011$ 是个质数,可提前预处理出阶乘及其逆元,AC code2 是这种做法,时间复杂度为 $O(n)$。
EZOJ51 黎曼函数
AC code
按照题意模拟,预处理出 $f(x)$ 的 $k$ 阶导函数即可。
注意模数是 $10^8+7$ 不是 $10^9+7$。
时间复杂度为 $O(kn+qn)$。
EZOJ52 树状数组套splay
AC code1
AC code2
离线做法很简单,将边权和询问都从大到小排序后,向图中不断加边,用并查集维护当前图中的连通块数即可。
如果强制在线呢?也不难想到选择边权尽量大的边答案一定不劣,所以直接 kruskal 找出最大生成树,保证能让最小的边的边权尽量大,然后对于每次询问二分出最多能用多少条边即可。
注意题目中没有保证图连通,这里所说的最大生成树不一定是连通的,所以设二分出能用 $k$ 条边,答案应为 $n-k$,与最大生成树的边数无关,然而 std 的柿子与边数有关便挂了,这里给出一组 hack 数据:
4 2 1
1 2 1
2 3 2
1
答案应该是 $2$,输出 $1$ 的是错的。
但是我发现出题人造的数据都是一棵树,所以也有可能数据保证图连通但是出题人没有写在题面上?
数据范围说好的 $n\le 10^5$,不知道为啥出题人造的数据 $n$ 最大才 $10^4$,导致在线做法跑得要比离线的快一些。
AC code1 是离线算法,时间复杂度为 $O(m\log{m}+q\log{q}+m\alpha(n))$。
AC code2 是在线算法,时间复杂度为 $O(m\log{m}+q\log{n}+n\alpha(n))$。
EZOJ53 SG函数
AC code
首先 $\dbinom{n}{m}$ 显然比 $\dbinom{n-1}{m}$ 要大,所以我们可以维护一个堆,每次贪心选最大的组合数。
现在难点在于如何比较两个组合数的真实大小,由于数字巨大没法存储真实数字,取模意义下显然也不对,所以可以考虑取对数:
$\log{\dbinom{n}{m}}=\log{\dfrac{n!}{m!(n-m)!}}=\log{n!}-\log{m!}-\log{(n-m)!}$
而 $\log{n!}=\sum\limits_{i=1}^{n}\log{i}$,所以我们存储 $\log$ 函数的前缀和即可,膜意义下的组合数可以提前预处理出阶乘及其逆元。
注意 $\log$ 要用浮点数存,需要 cmath 库里面的 $\log$ 函数。
虽然我用 pb_ds 的配对堆,ext/pb_ds/priority_queue.hpp 库包含了 cmath 库,但是还是建议用 $\log$ 函数就开 cmath 库。
时间复杂度为 $O((n+k)\log{(n+k)})$。
EZOJ57 主席树优化最小割
AC code
一开始打表发现了答案是斐波那契数列,直接矩阵快速幂求解即可,现在来证明一下:
$x\oplus 3x=2x$ 即为 $x\oplus 2x=3x$,而 $x+2x=3x$ 也成立,显然只有当 $x+2x$ 不进位时两个柿子才同时成立。
考虑到 $2x$ 就是 $x\ll 1$,所以 $x+2x$ 进位当且仅当 $x$ 在二进制表示下有相邻的 $1$。
于是就可以设 $f_{i,0/1}$ 表示没有相邻的 $1$ 且最后一位是 $0/1$ 的 $i$ 位二进制数,则有:
$f_{i,0}=f_{i-1,0}+f_{i-1,1}$
$f_{i,1}=f_{i-1,0}$
然后我们把第二个柿子变成 $f_{i-1,1}=f_{i-2,0}$ 并将其带入到第一个柿子中,省略掉第二维,可以得到:$f_i=f_{i-1}+f_{i-2}$。
这也就是斐波那契数列的柿子,证毕。
时间复杂度为 $O(\log{n})$。