CF题解合集

CF 比赛题解合集

目录

\(\downarrow 2023.09.04\)

CF1952, CF1954

1952

A. Ntarsis' Set

有一个集合,初始状态里面有数字 \(1\)\(2\)\(3\)\(4\)\(5\)、......、\(10^{1000}\)

现在给你一个长度为 \(n\) 数组 \(a (1\leq a_i \leq 10^9 )\),要进行 \(k\) 次操作,每次操作将当前集合中第 \(a_1\) 小、第 \(a_2\) 小、......、第 \(a_n\) 小的数同时移除。

请问 \(k\) 次操作之后,最小的数是多少。

顺难则逆。

考虑如果已知删除后在集合中的位置,可以很简单的找到删除前的位置。

所以已知初始的位置,也可以很简单的找到删除后的位置,\(O(n + k)\) 即可。

void work() {
    int n, k; cin >> n >> k;

    for (int i = 1; i <= n; ++i) cin >> a[i];

    lint i = 1, cur = 1, pre = 0;
    while (k--) {
        cur += pre;
        while (i <= n && a[i] <= cur)
            ++cur, ++i, ++pre;
    }

    cout << cur << '\n';
}

B. Imbalanced Arrays

对于一个给定的长度为 \(n\) 的数组 \(A\),定义一个长度为 \(n\) 的数组 \(B\) 是不平衡的当且仅当以下全部条件满足:

  • \(-n \leq B_{i} \leq n\)\(B_{i} \ne 0\)。即每个数在 \([-n,n]\) 内且不为 \(0\)

  • \(\forall i,j \in [1,n], B_{i} + B_{j} \neq 0\)。即数组内不存在一对相反数。

  • \(\forall i \in [1,n], \sum_{j = 1}^{n} [ \left (B_{i} + B_{j} \right) > 0] = A_{i}\)。即对于任意的 \(i\),数组中与 \(B_{i}\) 和大于 \(0\) 的数的个数恰好为 \(A_{i}\)注意:这里需要计算本身。也即 \(i\)\(j\) 可以相等。

请构造长度为 \(n\) 的不平衡序列。

两种方法,其一可以参见 hfjh

考虑递归的构造序列,如果当前存在 \(A_i = 0\) 或者 \(A_i = n\),那么其对应所填的数必定为 \(-n\) 或者 \(n\)

由于相反数不可能同时出现,所以两个不能同时存在,否则无解。

递归的构造即可。

代码链接:https://codeforces.com/contest/1852/problem/B

C. Ina of the Mountain

  • 给定一个长度为 \(n\) 的序列 \(a\) 和正整数 \(k\)

  • 每次可以选择一个区间 \([l,r]\)\(\forall i \in [l,r],a_{i} = a_{i} -1\)

  • 如果 \(a_{i} = 0\),则将 \(a_{i}\) 变为 \(k\)

求让序列全部为 \(k\) 的最小操作次数。

多组测试数据,\(1 \leq n \leq 2 \times 10^{5}\)

先不考虑 \(\bmod k\) 的情况,则构造差分序列 \(d\),答案即为:

\[\sum_{i} [d_i \gt 0]d_i \]

那么考虑每次 \(0 \to k\) 的变换,相当于在原序列上加了 \(k\),然后求上式。

考虑变成差分序列上加减。也就是有地方 \(+k\),有地方 \(-k\),使得上式最小。

所以考虑正负平衡一下即可。

代码链接:https://codeforces.com/contest/1852/submission/221761642

能考场切自是极好。

D. Miriany and Matchstick

你有一个 \(2\times n\) 的矩阵,第一行给定(字符串 \(s\)),你需要在第二行的位置填上 \(A\)\(B\)

你需要构造矩阵的第二行,使得该矩阵相邻的格子不同的个数恰好为 \(k\)

考虑很 naive 的 DP \(f_{i, 0/1, k}\) 表示填完前 \(i\) 个数,恰好为 \(k\) 是否可行。

打表可以发现,\(k\) 可行的集合至多为两个区间。

证明:每一次转移可以是 \(+1\) 或者 \(+2\),同时又是前面的两个区间并过来的,所以空缺只会是 \(0/1\) 个。

所以可以压成 \(f_{i, 0/1}\) 即可 /kel

\[f_{i, 0} = (f_{i - 1, 0} \cup (f_{i - 1, 1} + 1)) + (s_i \ne s_{i - 1}) \\ f_{i, 1} = ((f_{i - 1, 0} + 1) \cup f_{i - 1, 1}) + (s_i \ne s_{i - 1}) \]

所以可以用 bitset 对吧。

最后贪心的构造即可。

E. Rivalries

Ntarsis 有一个长为 \(n\) 的数组 \(a\)

定义一个子数组 \(a_l \cdots a_r\) 的权重为:

  • 在整个数组 \(a\) 中,只出现在该子数组 \(a_l \cdots a_r\)中的最大元素 \(x\)
  • 若不存在这样的 \(x\),权重为 \(0\)

称数组 \(b\)\(a\) 数组匹配,当且仅当满足:

  • \(2\) 者长度相等。
  • 数组 \(a\) 中的每个子数组的权重都与数组 \(b\) 对应的子数组的权重相等。
  • \(b\) 中的数都为正数。

最大化 \(b\) 的权值和。

\(1 \le n,t \le 10^5\)

考虑几个 hints

  • 对于每一个值,只有最左边和最右边的两个之外的区间可以做出贡献。

  • 将最左和最右记成二元组,如果存在 \(a_i \gt a_j\) 并且 \(i\) 完全被 \(j\) 覆盖,那么 \(j\) 将无法做出任何贡献。

  • 为了不改变权重,我们只可能增加上面所说的 \(j\) 区间。

  • 并且至多会有一个区间会加上某一个数。

1954

A. Dual

\(t\)\(1\le t\le 500\))组数据,对于每组数据给出一个长度为 \(n\)\(1\le n\le 20\))的序列 \(a\)\(-20\le a_i\le 20\))。

可以进行 \(k\)\(0\le k\le 31\))次操作,每次操作任选一组 \(i,j\)\(1\le i,j\le n\)),把 \(a_i\leftarrow a_i+a_j\),最后使得整个序列单调不减。

对于每组数据,第一行输出 \(k\),之后 \(k\) 行输出执行操作的 \(i,j\)

超级分讨。

考虑到全部变成正的,或者全部变成负的,然后前缀/后缀和即可,这需要 \(19\) 次。

首先找到绝对值最大的那个数。

如果异号的个数 \(\le 12\),那么直接加上即可。

反之,则同好的个数 \(\le 7\),那么找到最大的正数,做 \(5\) 次自加操作,然后加上去即可。

代码链接:Submission #221821611 - Codeforces

B. Earn or Unlock

有一长度为 \(n\) 的一副牌,每张牌上都有一个数字,设第 \(i\) 张牌上的数字为 \(a_i\)。初始时,你手里只有第一张牌。对于每一张牌,你有两种选择:

  • 如果剩余的牌数量 \(< a_i\),则将牌摸完,否则继续往下摸 \(a_i\) 张牌。摸牌完成后,这张牌会被丢弃。

  • 获得 \(a_i\) 的分数,并丢弃这张牌。

求你能获得的最大分数。

对于所有数据,保证 \(1 \le n \le 10 ^ 5\)\(0 \le a_i \le n\)

考虑如果可以摸完 \(k\) 张牌,由于摸一张牌的代价为 \(1\),所以得分为:

\[- k + 1 + \sum_{i = 1}^k a_i \]

所以判断哪些地方可以摸到即可。

考虑一个 naive\(O(n^2)\) DP。

有:

\[f_i |= f_{i - a_i} \text{~ then ~} f_i = 0 \]

于是可以考虑用 bitset 优化。

所以总的复杂度为 \(O(\frac {n^2} w)\)

代码:https://codeforces.com/contest/1854/submission/221792387

C. Expected Destruction

给定大小为 \(n\) 的正整数集合 \(S\)\(S\) 中的每个数在 \(1\sim m\) 之间。

每一秒进行如下操作:

  1. \(S\) 中等概率随机选择一个数 \(x\)
  2. \(x\)\(S\) 中删去。
  3. \(x + 1\leq m\)\(x + 1\notin S\),则将 \(x + 1\) 加入 \(S\)

\(S\) 变成空集的期望时间,对 \(10 ^ 9 + 7\) 取模。

\(1\leq n\leq m \leq 500\)\(1\leq S_1 < S_2 < \cdots < S_n \leq m\)

1843

Div. 3 果然简单,虽然但是,我还是有 1 道题没有想出来。

A.Sasha and Array Coloring

排序双指针向内即可。

https://codeforces.com/contest/1843/submission/210855587

B.Long Long

好啊,就是这道题没想出来。

Virtual Contest 上完成了一半。

考虑把符号相同(0 与任何数符号相同)的合并。

因为放在一起操作显然最优。

bool sgn_eq(int x, int y) {
    return (x * y) >= 0;
}

然后你就得到了一个 ... + - + - ... 正负交替的序列。

那么,很明显,正数与负数的个数相差不超过一,也就是说花费 1 的代价将负数转化为正数的行为是不可取的(我就死在这上面,如此弱智的东西……),于是记录所有负数的个数即可。

有可能溢出,要精细实现

https://codeforces.com/contest/1843/submission/211085413


也可以直接合并负数序列(忽略 0 的情况)

https://codeforces.com/contest/1843/submission/211082437

C.Sum in Binary Tree

会手写堆的人都会写……

Submission #210856724 - Codeforces

D.Apple Tree

弱智题……记录一下每一个节点有多少个叶子节点。输出相乘的结果即可。

https://codeforces.com/contest/1843/submission/210857337

E.Tracking Segments

其实可以改一下题目,变为:

对于每一条线段,求出其变成 beautiful segment 的时间,如果不会变,则输出 -1,顺便强制在线一波。这样代码难度递增。

我首先想到的是一个在线做法。

只要在这个区间内修改了严格大于一半的点,那么一个区间就变得 美丽

那么什么最早是什么时候?

定义序列 \(t_i\) 表示第 \(i\) 个点变成 \(1\) 的时间,如果没有修改则 \(t_i = \inf\)

对于区间 \([l, r]\),设 \(k = \lfloor \frac {l - r + 1} 2 \rfloor + 1\),则对于序列 \(t\) 的区间 \([l, r]\)\(k\) 小即为所求。

如果为 \(\inf\) 则不会变得 美丽

但是显然这太过于复杂。

考虑离线处理每一个线段,并且二分答案。

明显答案具有单调性,如果在 \(t\) 时变得 美丽,则之后一直会很 美丽

我说的不是我们

我们只加入前 \(mid\) 个点,然后用一个前缀和一一判断有没有 美丽 的线段即可。

如果是 美丽 的,则满足在这个区间内有 \(\ge k\) 个点变成了 \(1\)

https://codeforces.com/contest/1843/submission/211083551

F.Omsk Metro

自己做的时候胡的性质:

对于一个路径 \(p\),定义其最大子段和\(mx_p\)最小子段和\(mn_p\)

那么可以拼凑出来的区间为 \([mx_p, mn_p]\)

感性证明一下:

这里不妨把一条路径拍扁成一条链,设为 \([l, r]\)

我们考虑加入一个点 \(r\) 对于一条路径 \([l, r]\) 的影响。

\(suf_x\) 为以 \(x\) 为右端点,可以凑出来的权值的集合。

考虑递推,有 \(suf_x = \{0, w(x)\} \cup (suf_{x - 1} + w(x))\)

于是对于区间 \([l, r]\)\(S = \bigcup_{l \le x \le r} suf_x\)

其实不难发现,\(suf_x\) 的上下界每一次最多只会变化 \(1\),也就是说,如果可以凑出 \(x (x \ge 0)\),那么一定可以凑出 \([0, x]\)。负数的情况同理。

所以我们考虑求出最大的,和最小的子段和即可 \(O(1)\) 判断……

实现上也就是树链剖分加上基本的求区间最大子段和的思路即可。

1834

Virtual Contest 做了 5 道题,非常不错。

A.Unit Array

秒切题,判断个数,然后判断一下奇偶即可。

提交:https://codeforces.com/contest/1834/submission/211190220

B.Maximum Strength

题目描述

每一种材料的力量由一个十进制整数表示。

对于一个武器,由两种材料构成。假如第一种材料的力量为 \(X = \overline{x_1x_2 \dots x_n}\),第二种材料的力量为 \(Y = \overline{y_1y_2 \dots y_n}\),那么这个武器的力量为 \(\sum_{i = 1}^n |x_i - y_i|\),也就是 \(|x_1 - y_1| + |x_2 - y_2| + \dots + |x_n - y_n|\)

如果两个数字长度不一样,则要将短的数字用前导零补成相同长度

现在,你拥有无数个力量在 \([L, R]\) 中的材料。你想要选出两个材料做出一个力量最大的武器。请你求出你设计出的武器力量的最大值。

题解

找到第一个不同的地方,其他地方全部填 \(|9 - 0|\) 即可。

大数填 0,小数填 9,这样一定满足在区间内。

提交:Submission #211191108 - Codeforces

C.Game with Reversing

题目描述

你有两个长度为 \(n\) 的序列 \(S, T\)

你将不断重复以下步骤直到两个序列相等:

  1. \(S\) 或者 \(T\)任意选择一个数字,然后修改为另一个数字。如果此时序列相等,则结束操作,否则进入操作 \(2\)

  2. 任意反转一个序列。如果此时序列相等,则结束操作,否则重复操作 1。

注意:操作 \(1\) 和操作 2 都计入操作次数中。

你需要输出最小化的操作次数。

解题

正序和逆序分别讨论一下,取 \(\min\) 即可。

\(icnt\) 表示正序不同的个数,\(rcnt\) 表示逆序不同的个数。

那么 \(ans = \min(2 \times icnt - icnt \% 2, 2 \times rcnt - (rcnt - 1) \% 2)\)

提交:https://codeforces.com/contest/1834/submission/211198802

D.Survey in Class

对于每一个学生的学习集合,答案是 \(2 \times \max(|S_1| - |S_1 \cap S_2|)\)

\(O(n \log n)\)

考虑使用树状数组维护线段,从左向右扫一遍。

\(O(n)\)

考虑两条线段的关系,三种:

  • 左边

  • 相交

  • 右边

对于每一个 \(S_1\),我们需要最小化 \(|S_1 \cap S_2|\),所以对于三种情况,我们维护三个线段:

  • 右端点最左

  • 最短

  • 左端点最右

分别判断即可。

提交:Submission #211192375 - Codeforces

E.MEX of LCM

我考场上的做法

考虑只有 \(O(n^2)\) 个取值,那么 \(mex\) 一定 \(\le n^2\)。所以我们限制了答案的上界,设为 \(U\)

实际上有更紧的上界,根据:CF1834E MEX of LCM 题解 - LCTTTTTTTTTTT - 洛谷博客\(U\) 可以 \(= 4256233\)

考虑对于一个固定的右端点,其左端点与其匹配的 \(lcm\) 是单调的,并且不同的数量在 \(O(\log U)\)

考虑每一次变化 \(lcm\) 至少 \(\times 2\)

所以考虑用一个 set 维护。

同时,再用一个 set 维护所有出现过的 lcm (考虑是 \(O(n \log U)\) 个,空间没问题)

所以总复杂度为 \(O(n \log V \log U \log \log U)\)

提交:Submission #211194246 - Codeforces

还有的思路

考虑每一个左端点,可以二分找 lcm 的分界,当值大于上界的时候退出。

用桶或者什么东西操作一下即可。

复杂度为 \(O(n \log U \log n)\)

然而还有玄学优化,参考:出错了 - 洛谷,在 题解界面@Xy_top 的即可。

\(\downarrow 2023.09.06\)

1830

B. The BOSS Can Count Pairs

多组数据。

每组数据给你一个 \(n\) 和两个序列 \(a,b\)

求有多少个数对 \((i,j)\) 满足 \(1 \le i < j \le n\)\(a_i \times a_j = b_i + b_j\)

对于每一个 \(i\) 看作用 \(a_i \times x - b_i = y\) 这条线来切所有的点。

注意到当 \(a_i\) 很大的时候的简单的,我们只需要用一个桶记录一下 \((x, y)\) 的个数即可,然后可以 \(O(\frac n {a_i})\) 求出。

此时设一个阈值 \(B\),当 \(a_i \gt B\) 的时候认为是很大的,所以上面的复杂度可以看作 \(O(\frac n B)\)

问题在于当 \(a_i\) 很小的时候,注意到其实可以 \(O(B)\) 预处理出 \(\forall k \in [1, B]\) \(k \times a_i - b_i\) 的值。

这样就可以 \(O(1)\) 查询了。

两者稍微平衡一下,令 \(B = \sqrt {2n}\) 于是可以 \(O(n \sqrt {n})\) 解决本题。

代码链接: https://codeforces.com/contest/1830/submission/222008847

C. Hyperregular Bracket Strings

给定一个数 \(n\)\(k\) 个区间 \(\left[l_i,r_i\right]\in [1,n]\)

我们定义,对于一个长度为 \(n\) 的,仅由 () 组成的合法括号序列,如果它的每一个区间 \(\left[l_i,r_i\right]\) 内的子串都是合法括号序列,那么这个括号序列是好的

好的括号序列的数量,答案对 \(998244353\) 取模。

相交和包含的情况很 naive,重点在于如何处理。

类比 \(2023.09.05\) izumi,采用一个随机化异或的做法。

每一个区间附上一个神秘的权值,差分前缀一次。

如果异或权值相同,意味着需要形成一个合法括号,这预处理卡特兰数即可。

rapper 的讲解见:hfjh

代码链接:https://codeforces.com/contest/1830/submission/222007540

D. Mex Tree

给定一棵 \(n\) 个结点的树,点有点权,点权为 0 或 1。你需要给一种指定点权的方案,使得每一条路径的点权 \(\operatorname{mex}\) 之和最大。

\(n\le 2\times 10^5\),多组数据。

如果考虑跨越多种数的正贡献,发现很难。于是考虑块内的负贡献。

正难则反!!!!!!!!!!!!!!!!!!!!!!!哦

对于每一个连通块,考虑树形背包。

\[\begin{aligned} f_{x, i, 0} &\leftarrow \min(f_{x, i, 0} + f_{j, k, 1}, f_{x, i - k, 0} + f_{j, k, 0} + (i - k) \times k) \\ f_{x, i, 1} &\leftarrow \min(f_{x, i, 1} + f_{j, k, 0}, f_{x, i - k, 1} + f_{j, k, 1} + 2 \times (i - k) \times k ) \end{aligned} \]

关键结论是连通块的大小一定不会很大,否则减少的贡献太多了。

有证明在 \(n \le 2e5\) 小不会超过 \(258\)

代码:https://codeforces.com/contest/1830/submission/222027041

E. Bully Sort

对于一个非升序的排列 \(\{p_i\}\),定义一次操作为按顺序执行以下步骤:

  1. \(p_i\) 为排列中最大的满足 \(p_i\neq i\) 的数。

  2. \(p_j\) 为排列中最小的满足 \(i<j\) 的数。

  3. 交换 \(p_i\)\(p_j\)

可以证明在排列非升序的前提下总能找到满足条件的 \(i\)\(j\)

定义一个排列的权值为将其升序排序所需的操作次数,可以证明总能在有限次操作内将其升序排序,注意如果排列本身就是升序的那么其权值为零。

现在给定一个排列和若干次修改操作,求出每次修改后排列的权值,每个修改操作为交换排列中指定的两个数。

注意修改是永久的。

发现排序方式和冒泡排序很像,于是考虑与逆序对之间的关系。

发现每次交换 \((i, j)\) 使得逆序对的个数减少 \(2(j - i) - 1\)

发现 \(2(j - i)\) 这个东西很好,考虑交换会影响什么改变 \(2(j - i)\)

发现 \(\sum_{i = 1}^n |p_i - i|\) 符合要求。

发现两者最后都为 \(0\)

发现操作次数等于 \(\sum_{i = 1}^n |p_i - i|\) 与逆序对个数之差。

于是动态维护逆序对即可。

发现分块很优秀,\(O(n \sqrt{n \log n})\),虽然是正常的 \(O(n \log^2 n)\) 的树套树的四倍时间……

代码:https://codeforces.com/contest/1830/submission/222012835

1836

A.Destroyer

开个桶记录个数,看满不满足单调不上升即可。

B.Astrophysicists

辛辛苦苦写了这么久的文章就没了????烦死了。

自己做 Virtual Contest 的时候这道题打表打了半天(20min)才搞定……

题目大意

\(n\) 个人,\(k\) 个金币,每个金币价值 \(g\) 个银币。

良心公司要把这 \(k\) 个金币作为工资分给这 \(n\) 个人,但是没有办法平均分配,良心老板想出了分配规则:

  • 由你设定每个人分配的银币数 \(x_i\)

  • 你需要保证 \(\sum_{i = 1}^n x_i = k \times g\)

  • 老板会把银币数转化为金币发放,所以想出了以下规则:

    • \(r = x \mod g\),如果 \(r \ge \lceil \frac g2 \rceil\),那么公司会额外花费 \(g - r\) 个银币以凑出完整的金币(此时花费了 \(x + g - r\) 个银币)。

    • 反之,会吞掉这 \(r\) 个银币以凑出完整的金币(此时花费了 \(x - r\) 个银币)。

假定最终公司的花费为 \(p\) 个银币。你需要最小化 \(p\),并输出 \(k \times g - p\)

解题思路

如果开始没有思路,那么打表是一个很好的方法。

首先我们可以很轻易的得到一个 \(O(nkg)\) 的 DP 算法。

\(f_{x, i}\) 表示处理到第 \(x\) 个人,一共分配了 \(i\) 个银币公司省下的最多银币。

有转移方程:

\[f_{x, i} = \max_{0 \le j \le i} f_{x - 1, i - j} + w(j) \]

其中:

\[r = j \mod g \]

\[w(j) = \begin{cases} r - g &, r \ge \lceil \frac g2 \rceil \\ r &, r \lt \lceil \frac g2 \rceil \end{cases} \]

运行后输出 DP 数组,结合 \(m = \lceil \frac g2 \rceil - 1\)可以很轻易的发现规律:

最终的数组分为两个部分:

  • 第一个部分为 \([0, nm]\),下标与数值一一对应。

  • 第二部分为 \([-\lfloor \frac g2 \rfloor - m - nm, nm]\) 不断循环。


现在我们来严谨证明一下。

理想状态下,我们自然是给每一个人分发 \(m = \lceil \frac g2 \rceil - 1\) 个银币,这样就可以吞掉 \(nm\) 个银币。

但是可能存在一下两种情况:

  • 其实根本没有 \(nm\) 个银币,所以全部都分配到 \(\le m\) 个。所以全部可以吞掉。对应上文中第一部分。

  • 还剩下了 \(r = k \times g - nm\) 个银币。由于我们可以按照一个金币为单位再分配,所以我们只需要关注 \(r \mod g\) 的值。

    显然,如果把这些银币分给不同的人是不优的,因为破坏了老板吞掉更多人 \(m\) 个银币的美梦。

    所以这些银币应该全部分配给一个人,对于答案做出贡献 \(w(m + k \times g- nm) - m\)

    化简一下)对应上文中第二部分。

提交记录:https://codeforces.com/contest/1836/submission/211134556

C.k-th equality

注意,注意:

Each input file has at most 5 test cases which do not satisfy A,B,C≤3.

所以,\(O(10^{\min(A, B)})\) 可以过。

那么考虑顺序枚举 \(A\) 位的数 \(a\),满足的数 \(b\) 应该为一个连续区间,这个可以 \(O(1)\) 解决。

所以区间长度与 \(k\) 判断一下即可。

提交记录:https://codeforces.com/contest/1836/submission/211137329

1835

B. Lottery

给定一个长度为 \(n\) 的序列 \(v\),其值域为 \([0,m]\)

现在你需要选择一个 \(x \in [0,m]\),使其权值最大。定义一个数 \(x\) 的权值为:

\[\sum_{c=0}^{m}[\sum_{i=1}^{n}[\vert v_i - c \vert \leq \vert x - c \vert] < k] \]

请你找到权值最大的数 \(x\),若有多个,输出最小的那个。

考虑 \(k = 1\) 的特殊情况,发现两个人内部的所有点都造成了 \(\frac 12\) 的贡献。所以告诉我们不需要枚举太多的点,在一些点的周围枚举一下即可。

这可以很合理的外推到所有的 \(k\) 的情况。

C. Twin Clusters

给定 \(2^{k+1}\)\([0,4^k)\) 内的整数,请求出任意两个不交非空区间使得其异或和相等,若无解则输出 -1

抽屉原理抽象题。-1 是不可能的,这一定有解。

于是考虑生日悖论,随机化一些区间即可(逃。

考虑正解,将 \(4^k\) 分成前 \(k\) 位和后 \(k\) 位。

前缀异或和有 \(2^{k + 1} + 1\) 个,而前 \(k\) 位最多有 \(2^k\) 种取值。所以至少会有 \(2^k + 1\) 对前 \(k\) 位相等的前缀。

考虑把这些对找出来,其后 \(k\) 位却也只有 \(2^k\) 种取值,所以至少有两对的后 \(k\) 位的异或值相等。所以就完了。

代码:https://codeforces.com/contest/1835/submission/222050899

D. Doctor's Brown Hypothesis

给定一张 \(n\) 个点 \(m\) 条边的简单有向图和常数 \(k\),请求出有多少组 \((x,y)\) 满足 \(1\le x\le y\le n\) 且存在一条 \(x\)\(y\) 和一条 \(y\)\(x\) 的长为 \(k\) 的路径,\(k\ge n^3\)

发现 \(n^3\),所以发现可以随便走环凑最小公约数。

于是先缩点,在连通块内考虑。

找出生成树,考虑一个非树边,有结论,\(d | \mathrm{abs}(dep_y - dep_x - 1)\)

所以可以找出 \(d\),而合法当 \(k \equiv 0 \pmod d\) 或者 \(d \equiv 0 \pmod 2 \text{ and } k \equiv \frac d2 \pmod d\)

用桶记录一下即可。

代码:Submission #222076413 - Codeforces

1827

A. Counting Orders

简单计数。

两个都排序,双指针维护一下 a[i]b[p] 的位置(a[i] <= b[p])。

那么方案数 \(\times (p - i)\)

提交:https://codeforces.com/contest/1827/submission/211387552

C. Palindrome Partition

回文好题

考虑利用 Manacher 求出每一个偶数的回文串。

参考:算法学习笔记(13): Manacher算法 - jeefy - 博客园

观察可以发现:每一个合法的串都可以被划分为多个最小的合法串,并且划分方法是唯一的。

所以考虑如下:

我们需要维护出每一个点作为右端点,最靠近的左端点。

这等价于求出满足 \(i + p[i] \ge x\),求 \(\max i\)

然后,设上面对于端点 \(i\) 求出来的结果为 \(g_i\)

得出最终的递推式:

\[f_i = \begin{cases} 0 &,g_i = 0 \\ f_{i - g_i} + 1 &, g_i \ne 0 \end{cases} \]

其中 \(f_i\) 表示以 \(i\) 结尾的合法的串的个数。

最终的答案为 \(\sum f_i\)

提交:Submission #211396680 - Codeforces

D. Two Centroids

性质好题

重心有如下性质:

  • 最大子树大小 \(\le \lfloor \frac n2 \rfloor\)

  • 新增一个叶子节点,重心最多变化一条边。

  • 重心至多有两个。

那么我们考虑每次加入一个点对于原来重心 \(c\) 的影响,并设当前最小的子树大小为 \(mx\)

  • 如果加入的叶子节点在 \(c\) 的子树 \(t\) 内。更新 \(t\) 的大小,并更新 \(mx\)。如果此时 \(mx \ge \lfloor \frac n2 \rfloor + 1\),那么重心向 \(t\) 移动。并且此时 \(mx\) 更新为 \(\lfloor \frac n2 \rfloor\)不考虑,把图画出来就明白了

  • 由于我们不可能动态维护以每一个重心为根,所以还要考虑其祖先的情况(同理)。

然后就是如何找 \(t\) 的问题。有两种解决方案:

  • 无论如何首先可以通过 dfn 序判断是否在其子树内。

    • 方案1:利用倍增的方法跳祖先。空间复杂度 \(O(n \log n)\),单次 \(O(\log n)\)

    • 方案2:利用 dfn 区间,对于每一个节点保存其子节点的 dfn,每次二分找到叶子的 dfn 所在的区间即可。(我用的这种方法)空间 \(O(n)\),单词 \(O(\log n)\)

  • 实测第二种要快一点点(也快不了多少,主要是常数够好)

提交:Submission #211401150 - Codeforces

E. Bus Routes

差点没用 dlang 卡过去

思路1

考虑更严的限制(等价):叶子节点间两两可以在两次内到达。

于是考虑对于每一个叶节点,求出其能到达的最高的祖先 \(high(x)\)

也就是求一个 LCA 即可。

那么满足条件的必要条件是每一对 \(high(x), high(y)\) 满足祖先/子节点关系。

如果不是,那么至少需要三条路径。

如果满足上述条件,那么所有的 \(high\) 满足在一条链上。

那么可以通过 dfn 序判断。

这并不充分。

考虑找到最低那个 \(high(x)\),并以 \(high(x)\) 作为根。

此时重新求一次 \(high\),如果所有的 \(high\) 都为 \(high(x)\),那么就是 \(ok\) 的,否则,如果有 \(high(y) \ne high(x)\),那么 \(x, y\) 不可达。

不要写倍增求 LCA,利用 ST表 \(O(n \log n) \sim O(1)\) 或者 树链剖分 \(O(n) \sim O(\log n)\) ,甚至是离线 \(O(n)\) 求。倍增太慢了,dlang 卡不过去。

思路2

参考 Alex_Wei 的博客:https://www.luogu.com.cn/blog/_post/575397

利用 DSU on tree

思路3

维护虚树并树上差分。非常的高效。

参考:CF1827E Bus Routes - Kubic 的博客 - 洛谷博客

1824

LuoTianyi and the Show

\(n\) 个人观看一场与 VOCALOID 有关的演出,场地里有一行座位,从左到右标号 \(1\)\(m\),接下来观众将按顺序以如下三种方式中的一种选择座位:

  1. 如果没人坐在座位上,就坐在座位 \(m\) 上,否则坐在目前最靠左的人的左边。若座位 \(1\) 有人,则离开。
  2. 如果没人坐在座位上,就坐在座位 \(1\) 上,否则坐在目前最靠右的人的右边。若座位 \(m\) 有人,则离开。
  3. 如果 \(x_i\) 没人则坐在 \(x_i\),否则离开。

现在知道每个人选择座位的方式,你可以让人们按照任意顺序入场,求最多找到座位的人数。

安排方式只有三种,1/2/3 分别先,依次向左/向右/向两边扩展即可。

LuoTianyi and the Floating Islands

给定一棵 \(n\) 个结点的树,现在有 \(k(k\le n)\) 个结点上有人。

一个结点是好的当且仅当这个点到所有人的距离之和最小。

求在这 \(n\) 个点中随机取 \(k\) 个点时,好的结点的期望个数,对 \(10^9+7\) 取模。

发现用点来算很难算,于是考虑用边来算贡献。由于每种情况边会比点数少 \(1\),所以期望点数等于期望边数 \(+1\),于是考虑边如何做贡献,两边的点数相等即可。

于是就搞定了:https://codeforces.com/contest/1824/submission/222881710

LuoTianyi and XOR-Tree

给定一棵 \(n\) 个节点的树,根节点为 \(1\) ,每个点有一个点权 \(a_i\) ,每次操作可以选择一个点任意修改点权,求最少的操作次数,使得每一条根结点到叶子结点的路径上的异或和都为 \(0\)

如果要相等,那么只需要子树所有相等,那么改变只需要改变自己即可。

所以找到子树中最多的那个值,保留即可。

并且启发式合并即可……

代码:https://codeforces.com/contest/1824/submission/222885893

注意 if (maxcnt > 1) 的优化,否则会 TLE。

LuoTianyi and the Function

Feyn 给了你一个长度为 \(n\) 的整数数组 \(a\),下标由 \(1\) 开始。

用以下方式定义函数 \(g(i,j)\)

  • \(i\le j\) 时,\(g(i,j)\) 是满足 $ {a_p:i\le p\le j}\subseteq{a_q:x\le q\le j} $ 的最大整数 \(x\)
  • 否则 \(g(i,j)=0\)

\(q\) 次询问,每次给定 \(l,r,x,y\),请求出 \(\sum\limits_{i=l}^r\sum\limits_{j=x}^y g(i,j)\) 的值。

需要个可以区间赋值和历史版本求和线段树……不会额。

\(\downarrow 2023.09.11\)

1819

A. Constructive Problem

给定整数 \(n\) 和一个非负整数序列 \(a\)

你需要选择整数 \(l,r,k(1\leq l\leq r\leq n;0\leq k)\),然后将 \(a_l,a_{l+1},\cdots,a_r\) 的值均变为 \(k\)

判断能否通过恰好一次上述操作使操作后的 \(\mathrm{mex}(a)\) 增加 \(1\)

如果没有 \(\mathrm{mex}(a) + 1\) 的存在,并且 \(\mathrm{mex}(a) \lt n\),那么一定存在方案。

否则,需要变换所有的 \(\mathrm{mex}(a) + 1\),而为了使影响最小,只是恰好包含所有的区间变成 \(\mathrm{mex}(a)\),重新求一次 \(\mathrm{mex}\) 即可。

代码:https://codeforces.com/contest/1819/submission/222839488

B. The Butcher

有一张 \(h\times w\) 的纸片,但你并不知道 \(h\)\(w\) 的具体数值。现在对这张纸片进行 \(n-1\) 次裁剪。每次裁剪后会将其中一半收归(即这一半不会再被裁剪),保证纸片不会被旋转。

告诉你最终裁剪后的 \(n\) 张纸片长宽,问初始有多少 \(h\times w\) 的纸片可以裁剪成这 \(n\) 张纸片,输出所有可行的 \((h,w)\)

发现一张一定是 \(h\) 或者 \(w\),那么找到 \(\max h\)\(\max w\) 作为两种可能即可。

由于每次减下 \(w, h\) 递减,所以考虑双指针扫一遍即可。

代码:https://codeforces.com/contest/1819/submission/222845297

C. The Fox and the Complete Tree Traversal

给定整数 \(n\) 和一棵包含 \(n\) 个节点的树。

\(\text{Dist}(x,y)\) 表示树上节点 \(x,y\) 之间最短路径的边数。

你需要判断是否存在一个 \(1\sim n\) 的排列 \(p\),满足:

  • \(\text{Dist}(p_i,p_{i+1})\leq 2\) 对任意整数 \(i(1\leq i<n)\) 成立。
  • \(\text{Dist}(p_1,p_n)\leq2\)

存在则输出 Yes 然后输出任意一个满足要求的 \(p\),不存在则输出 No

有两种方法,一种是我考场想出来的,分讨比较严重:

先考虑状态 \(f_{x, 0/1}\) 表示走完其子树后是否可以在其子节点或者本身上。

发现叶子节点对于其可行性没有影响,考虑非叶节点的影响。

不难分类讨论,设当且节点为 \(x\)

  • 如果没有非叶节点,那么不难发现最后无论在哪里都可以。
  • 如果只有一个非叶节点 \(y\),那么发现 \(f_{x, 0}\) 满足当且仅当 \(f_{y, 1}\) 满足,同理,\(f_{x, 1}\) 满足当 \(f_{y, 1}\) 满足。
  • 如果有两个非叶节点,发现除非这个点是根,或者父节点为根且根没有其他子树,否则绝对无法满足。而如果满足上述条件,那么最开始无论是从 \(x\) 出发,还是最终到达 \(x\) 本质相同。

所以我们可以愉快的 DP 了,但是考虑父节点为根且根没有其他子树的情况不太好判断,所以任意找一个度数 \(\ge 2\) 的点作为根,那么自然这个条件就无法满足,如果没有找到……这还是能一颗树?

int rt = 1;
void dfs(int x, int p) {
    dep[x] = dep[p] + 1;

    int son = 0;
    vector<int> nonleaf; 
    for (int y : G[x]) {
        if (y == p) continue;
        ++son;
        dfs(y, x);
        if (!leaf[y]) nonleaf.push_back(y);
    }

    if (son == 0)
        leaf[x] = 1, f[x][1] = 1;
    else if (nonleaf.size() == 0) 
        f[x][0] = f[x][1] = 1;
    else if (nonleaf.size() == 1) {
        int y = nonleaf[0];
        f[x][0] = f[y][1], f[x][1] = f[y][0];
    } else if (x == rt && nonleaf.size() == 2) {
        int y = nonleaf[0], z = nonleaf[1];
        if ((f[y][0] && f[z][1]) || (f[y][1] && f[z][0])) f[x][1] = true;
    }
}

这样,从根开始,依据 DP 转移的过程构造即可。

vector<int> v;
void construct(int x, int t, int p) {
    vector<int> nonleaf;
    for (int y : G[x]) {
        if (y != p && !leaf[y]) nonleaf.push_back(y);
    }

    #define pushLeaf() { for (int u : G[x]) if (u != p && leaf[u]) v.push_back(u); }
    if (nonleaf.size() == 0) {
        if (t == 0) v.push_back(x);
        for (int y : G[x]) {
            if (y != p) v.push_back(y);
        } if (t == 1) v.push_back(x);
    } else if (nonleaf.size() == 1) {
        int y = nonleaf[0];
        if (t == 0) {
            v.push_back(x);
            construct(y, 1, x);
            pushLeaf();
        } else {
            pushLeaf(); 
            construct(y, 0, x);
            v.push_back(x);
        }
    } else if (nonleaf.size() == 2) {
        int y = nonleaf[0], z = nonleaf[1];
        v.push_back(x);
        if (f[y][1] && f[z][0]) {
            construct(y, 1, x);
            pushLeaf();
            construct(z, 0, x);
        } else if (f[y][0] && f[z][1]) {
            construct(z, 1, x);
            pushLeaf();
            construct(y, 0, x);
        } else assert(nonleaf.size() == 2);
    }
}

虽然是说稍微复杂了一点,但是分讨很简单,代码依据分讨就可以直接模拟出来,十分的 naive,这比正解要更 brute force 一点(CF优良传统)。

而对于正解,先找出最长链,那么支链的深度不能超过 \(1\),否则一定不合法,\(O(n)\) 做即可,只是要扫很多遍而已。

D. Misha and Apples

给定 \(n\) 个集合 \(S_i\),第 \(i\) 个集合的大小为 \(k_i\),集合元素为 \(1\sim m\) 的正整数。特别地,若 \(k_i = 0\),则 \(S_i\) 可以是正整数 \(1\sim m\) 的任意可空子集,由你确定

可重集 \(S\),初始为空。按编号从小到大依次遍历每个集合,往 \(S\) 中加入 \(S_i\) 所有元素。每次加入当前集合的所有元素后,若 \(S\) 包含重复元素,则清空 \(S\)。注意,一个集合内的元素 同时 被加入 \(S\)

你需要确定 \(k_i = 0\)\(S_i\) 具体包含哪些数,使得最终的 \(|S|\) 最大。求出这个最大值。

\(1\leq T, \sum n, m\leq 2\times 10 ^ 5\)\(0\leq \sum k_i\leq 2\times 10 ^ 5\)\(S_i\) 的元素互不相同。

考虑找到可以清空的位置 \(can_i\),以及每一个 \(i\) 往前最多可以保留到的位置 \(late\)

每次找到最后一个冲突的位置 \(max\_conflict\) 记为 \(mc\),于是如果 \(mc \le late\) 那么对于 \(late\) 没有影响,而 \(can_i\) 可行当且仅当 \((late, i]\) 之间存在一个 \(k = 0\)

否则 \(can_i\) 一定可行,而 \(late\) 需要更新到 \(mc\) 之后第一个 \(can_i\)\(1\) 的点。

于是,就搞定了。

E. Roads in E City

这是一道交互题

给定一张 \(n\) 个点 \(m\) 条边的无向连通图,无自环,但可能有重边。

图上有一些特殊边,保证任意两个结点通过特殊边连通,你希望求出所有特殊边。

初始所有边都没有被堵住。你可以进行以下三种操作:

  • \(-\ x\)\(1\leq x\leq m\)):如果第 \(x\) 条边没有被堵住,则堵住该边。
  • \(+\ x\)\(1\leq x\leq m\)):取消堵住第 \(x\) 条边。操作前第 \(x\) 条边必须被堵住。
  • \(?\ y\)\(1\leq y\leq n\)):交互库随机选择某个 \(s\) 并返回能否从 \(s\) 出发走没有被堵住的特殊边到 \(y\)

你最多进行 \(100m\) 次操作。

\(2\leq n\leq 2000\)\(n - 1\leq m\leq 2000\)\(1\leq t\leq 1000\)\(\sum n, \sum m\leq 2000\)。保证图无自环且连通。

利用其随机化,以及联通的性质。

找到一个特殊的生成树,然后考虑非树边即可。

问题在于如何判断树边,断开,然后两边跑 \(k\) 次,那么错误率为 \((\frac x n \frac {n - x} n)^k\),在 \(k \to 20\) 的时候就趋近于 \(0\) 了,可以认为完全正确。

于是就做完了。

\(\downarrow 2023.09.18\)

1817

A. Almost Increasing Subsequence

给定长度为 \(n\) 一个序列 \(a\) 以及 \(q\) 次询问,每次询问给出 \(l\)\(r\),找出序列 \(a\)\([l,r]\) 内最长的几乎递增子序列。

对于几乎递增的定义:如果一个序列中不存在连续的三个数 \(x\)\(y\)\(z\),使得 \(x \ge y \ge \ z\),则这个序列是几乎递增的。

也就是说每一段递减的都至多取两个。转换一下,减去连续的三个的个数,差分一下即可。

代码:https://codeforces.com/problemset/submission/1817/223787996

B. Fish Graph

定义“鱼图”为满足以下条件的无向图:

  • 该图包含正好 \(1\) 个环,环上有 \(1\) 个特殊的结点 \(u\)\(u\) 除了连在环上的 \(2\) 条边外还有正好 \(2\) 条边,每一条边连向一个环外的结点(即,若环的大小为 \(s\),整个图一共有 \(s+2\) 个结点)。

现在给定一个简单无向图,问该图中是否有一个子图为“鱼图”。一个无向图的子图即为原图中删去若干个点和若干条边所形成的图。如果存在,还需要构造出其中任意一个满足要求的子图。

合法的点当且仅当 \(D_x \ge 4\) 并且 \(SCC_x \ge 3\),于是可以 \(O(n)\) 求了。

注意我的写法中,需要回退,防止 \(<><>\) 的这种图找不到环。

代码:https://codeforces.com/problemset/submission/1817/223785932

C. Similar Polynomials

给定两个次数为 \(d\) 的多项式 \(A, B\)\(0, 1, 2, \dots, d\) 处的点值对 \(10^9+7\) 取模,保证 \(B(x) \equiv A(x+s) \pmod {10^9+7}\)。求 \(s \bmod 10^9+7\)

考虑差分:

\[\begin{aligned} \Delta^{n - 1}f &= a(x + s) + b \\ \Delta^{n - 1}g &= ax + b \\ \Delta^{n}f &= \Delta^{n}g = -a \\ \end{aligned} \]

于是可以求出 \(s\) 了。

还有拉格朗日插值求出系数然后求的方法,差不多。

代码:https://codeforces.com/problemset/submission/1817/223798973

D. Toy Machine

有一个长 \(n\)\(2\) 的矩形游戏机。保证 \(n\) 是奇数。

游戏开始之前,有 \(n - 2\) 个玩具放在第一排中间的 \(n - 2\) 个位置中(两个角除外)。编号从左到右依次为 \(1\)\(n - 2\)。第二行为空,其最左、最右和中心位置是障碍物。你可以控制玩具机向左、向右、向上、向下,分别用字母 \(\texttt L\)\(\texttt R\)\(\texttt U\)\(\texttt D\) 表示。

操控时,所有玩具将同时沿相应方向移动,碰到另一个玩具、墙壁或障碍物停止。您的目标是将第 \(k\) 个玩具移动到第一行最左边。给定 \(n\)\(k\),构造一个最多使用 \(1000000\) 次操作的方案。

认为代码展示了一切:https://codeforces.com/problemset/submission/1817/223803543

E. Half-sum

有一个非负整数序列 \(\{a_1,a_2,\dots,a_n\}\)

你可以从序列中取任意两个数,并将它们的平均数放回序列。

序列最后会剩两个数,请求出这两个数的差的绝对值的最大值。

因为答案将会是一个小数,所以请输出答案对 \(10^9+7\) 取模的结果。

呃,推一点点式子,发现如果从断点 \(x\) 到断点 \(y\) 的差距为:

\[\sum_{i = x + 1}^{y} (\frac {a_i}{2^i} + \frac {a_i}{2^{n-i+1}}) - \frac {a_x}{2^x} + \frac {a_y}{2^y} + \frac {a_{x + 1}}{2^{n - x}} - \frac {a_{y + 1}}{2^{n - y}} \]

于是可以 \(O(y - x + 1)\) 求解,于是发现可以分治求解。

问题在于如何维护这些加加减减的值。

有一个 trickTrygub Number,适用于此。

于是可以 \(O(n \log n)\) 求解了。

注意可能需要较快的读入:Submission #223847308 - Codeforces

然而正解,考虑 \(2^i\)\(i \ge 30\) 时便很大了,使得 \(\frac {a_i}{2^i}\) 趋近于 \(0\),于是可以发现断点只会出现在前/后 \(\log n\) 个不同的数上,于是常数为 \(64\)\(O(n)\) 做法新鲜出炉!

1815

Div. 1 确实难,Virtual Contest 上只完成了两道题,想出来了三道题。

A. Ian and Array Sorting

秒切题……考虑将前 \(n - 1\) 个数变成一样的一个数 \(x\)。显然可以完成。

然而考虑此时最后一个数。如果 \(\ge x\),那么是 \(\texttt{\colorbox{#52C41A}{\textcolor{white}{AC}}}\),如果 \(\lt x\),要分类讨论:

  • 如果前面有奇数个,是 \(\texttt{\colorbox{#E74C3C}{\textcolor{white}{WA}}}\)

  • 反之,则是 \(\texttt{\colorbox{#52C41A}{\textcolor{white}{AC}}}\)

提交:Submission #211291004 - Codeforces

B. Sum Graph

傻逼交互

好呀好呀,傻逼交互体。想出来了思路,但是就是没有写出来。

考虑 +\(n + 1, n + 2\)。那么整个图会形成一条链。

static int perm[N]; int l = 1, r = n;
for (int i = 1; i <= n; ++i) {
    perm[i] = (i & 1) ? l++ : r--;
}

于是我们可以在 \(n - 1\) 次以内找到链的一端,然后就可以再来 \(n - 1\) 次找到可能的排列。

由于我们可能是找到的两端,所以有两种排列方法。

输出即可。

提交:Submission #211296415 - Codeforces

进阶:参考 https://codeforces.com/blog/entry/114847?#comment-1021812 以及 Editorial of Codeforces Round #865 - Codeforces,可以把次数减少到 \(n + \lfloor \frac n2 \rfloor + 2\) 次询问。

C. Between

构造好题

考虑包含可以形成依赖。

于是可以形成一张图。

我们从 1 开始 BFS 对其分层,可以发现,第 \(i\) 层最多可以放 \(i\) 个(包含依赖多套一个)。

那么考虑如何构造合法方案。

我的方法是每一次,按照 BFS 逆序遍历很多遍,每一次遍历到,如果还有没放的则放一个,否则略过。(好像官方题解就是这样?看不懂)

考虑正确性:按照逆序遍历保证出现次数少的在中间,保证不同层之间的依赖关系;每次放一个保证出现次数相同的交替出现,这样就保证了层内的依赖关系无论如何一定满足(互相依赖也没关系)。

提交:Submission #211298131 - Codeforces

D. XOR Counting

打表好题

\(m = 1\) 的时候答案就是 \(n\)

\(m \gt 3\) 的时候小小打表,可以发现答案为 \(\lceil \frac n2 \rceil \times (\lfloor \frac n2 \rfloor + 1)\)

证明:在 \(m \gt 3\) 的时候,\([x, \frac {n-x}2, \frac {n-x}2, 0, 0, \dots]\) 可以恰好凑出 \(x\),所以所有与 \(n\) 奇偶性相同的 \(x\)(此时 \(n-x\) 为偶数,\(\frac {n-x}2\) 为整数)都可以被凑出。

然后我们发现,加法和异或得到的奇偶性是一样的,并且有 \(a \otimes b \le a + b\),意味着我们只能凑 \(\le n\) 并且与 \(n\) 奇偶性相同的数。

综合两条,我们便可以得出,所有可能凑出的数就是 \(\le n\) 且与 \(n\) 奇偶性相同的数。

推一下公式就是上面的了。

于是问题就只剩下了 \(m = 2\) 的时候。

我们考虑一个 DP,我们记 \(f(n)\) 表示所有可能的异或和的和,\(g(n)\) 表示可能的个数。然后稍微分类讨论一下:

  • 如果 \(n\) 是奇数,我们不妨假设 \(n = a_1 + a_2\),其中 \(a_1\) 为偶数,\(a_2\) 为奇数。设 \(a_1' = \frac {a_1}2, a_2' = \frac {a_2 - 1}2\)。我们可以看出:\(a_1' + a_2' = \frac {n-1}2\) 以及 \(a_1 \otimes a_2 = 2 \times (a_1' \otimes a_2')+1\)。此时个数不会变,而和变为原本的两倍再加上个数。也就是 \(g(n) = g(\frac {n-1}2)\) 以及 \(f(n) = 2f(\frac {n-1}2) + g(\frac {n-1}2)\)

  • 如果 \(n\) 是偶数,那么我们又要分两类讨论:

    • \(n = a_1 + a_2\),其中两者都是偶数,那么类似的,\(a_1' + a_2' = \frac n2\)\(a_1 \otimes a_2 = 2 \times (a_1' \otimes a_2')\)

    • 如果都是奇数,有 \(a_1' + a_2' = \frac n2 - 1\) 以及 \(a_1 \otimes a_2 = 2 \times (a_1' \otimes a_2')\)

    • 因此,我们可以知道 \(f(n) = 2 \times f(\frac n2) + 2 \times f(\frac n2 - 1)\),以及 \(g(n) = g(\frac n2) + g(\frac n2 - 1)\)

FAKE: 于是我们可以得出递推复杂度 \(T(n) = T(\frac n2) + 1\),得出为 \(O(\log n)\)

依据SMB,复杂度似乎不是这样的,但是题解是这么给的,或许是有一些神秘的分析,或者是加了记忆化,所以复杂度是这样的。

其实完全可以用记忆化……快一点吧。

提交:https://codeforces.com/contest/1815/submission/211297560

E. Bosco and Particle

性质好题

性质:

  1. 循环多次 \(=\) 循环一次

  2. \(a_i\) 表示实际上从上面进入这个序列的次数,\(b_i\) 表示实际上向下面出去这个序列的次数。我们把第 \(i\) 个序列单独提出来,类似的定义 \(a_i'\)\(b_i'\)。可以发现,\(\exists k \implies a_i = ka_i', b_i = kb_i'\),也就是有 \(\frac {a_i}{b_i} = \frac {a_i'}{b_i'}\)

  3. \(a_i = b_{i-1}\)

  4. \(f_i = a_{i + 1}\)\(f_0 = a_1\),于是有 \(f_k = \prod_{i = 1}^k \frac {b_i}{a_i} f_0\)

  5. 需要保证 \(\forall k\),$ f_k$ 为整数。

于是就可以写出来啦!!!(不是

提交:Submission #211323975 - Codeforces

竟然比 C++ 快,不可思议

1868

A. 2D Traveling

该题共有 \(t\) 组数据,对于每一组数据,给定一个共有 \(n\) 个节点的图,其中有 \(k\) 个关键点(两个关键点之间移动花费为0)。给出 \(n\) 个点的坐标 \((x_i,y_i)\) ,求从 \(a\)\(b\) 两点之间的最小移动花费。

除关键点以外,两点之间的移动花费为曼哈顿距离

策略要么是 \(a\) 直接到 \(b\),要么是 \(a\) 先到最近的关键点,跳到 \(b\) 最近的关键点。

直接做即可,代码:https://codeforces.com/contest/1869/submission/223695140

B1/2. Candy Party

\(n\) 个人,第 \(i\) 个人有 \(a_i\) 颗糖,在派对上,每个人 会且仅会做下面的事情恰好一次

  • 选一个正整数 \(p\ (\ 1 \leq p \leq n\ )\) 和一个非负整数 \(x\) ,然后把 \(2^x\) 颗糖给第 \(p\) 个人。注意任意时刻一个人手上的糖不能变成负数,并且一个人不能把糖给自己。

你需要回答能否在上述操作后让每个人手中的糖果数量相同。

注意本题和 Hard Version 不同的是本题中每个人必须从他人处接受恰好一次糖果,给出恰好一次糖果。

也就是每一个人要么使用 \(2^x - 2^y\),要么使用 \(2^x\),要么使用 \(2^{2x} - 2^x\)。分开考虑来 DP 即可。

C. Travel Plan

给定一颗 \(n\) 个节点的完全二叉树,每个点有权值 \(a_i \in [1,m]\),定义从 \(i\)\(j\) 的路径的权值 \(s_{i,j}\) 为路径上的最大点权。

求所有树(\(m^n\) 种点权)的 \(\sum_{i=1}^n \sum_{j=i}^n s_{i,j}\) 的和,模 \(998244353\)

很显然,我们可以分别求出每种长度路径对答案的贡献,然后再在树上统计各个长度路径的个数,最后把贡献加起来即为答案。

D. Flower-like Pseudotree

给你一个基环树,我们称一个基环树是像花的当且仅当删去基环树中的环后,剩余的所有树高度一致,请你构造一个像花的基环树,满足树中所有点的度数为 \(d_i\)

大力分讨即可。

1863

A. Channel

Link

没什么好说的,模拟即可。

代码:https://codeforces.com/problemset/submission/1863/225013381

B. Split Sort

给定一个 \(1 \sim n\) 的排列 \(q\),你可以多次进行以下操作:

  • 新建一个初始为空的序列 \(q\)
  • 选择一个整数 \(x\)\(2 \leq x \leq n\));
  • 按照在 \(p\) 中出现的顺序将所有小于 \(x\) 的数添加到序列 \(q\) 末尾。
  • 按照在 \(p\) 中出现的顺序将所有大于等于 \(x\) 的数添加到序列 \(q\) 末尾。
  • 用序列 \(q\) 替代排列 \(p\)

你需要找到使 \(\forall i \in [1,n]\)\(p_{i} = i\) 的最小操作次数。

本题有多组测试数据,\(1 \leq T \leq 10^{3}\)\(1 \leq n,\sum n \leq 10^{5}\)

\(i\) 出现的位置为 \(p_i\),则答案为 \(\sum_{i = 2}^n [p_i < p_{i - 1}]\)

代码:Submission #225039544 - Codeforces

C. MEX Repetition

给定值域在 \([0, n]\) 的一个序列,\(p_i\) 互不相同,定义一次操作为 \(i = 1 \to n, p_i = \mathrm{mex}(P)\),求 \(k \le 10^9\) 后的序列是什么样子的。

将初始的 \(\mathrm{mex}\) 放在序列开头,则一次操作相当于 \(i = 1 \to n, \mathrm{swap}(p_0, p_i)\),结果是加入了 \(\mathrm{mex}\) 的序列向右循环了一次。

所以最后就是循环 \(k\) 次,去掉第一个数即可。

代码:https://codeforces.com/problemset/submission/1863/225014759

D. Two-Colored Dominoes

有一个 \(n \times m\) 的棋盘,上面铺着一些 \(1 \times 2\) 的多米诺骨牌(横竖均有可能),骨牌之间没有重叠。

你需要找到一种染色方案满足以下条件:

  • 每个多米诺骨牌一端被染白,另一端被染黑。其他没有骨牌的格子不染色。
  • 对于棋盘的每一行,被染黑的格子数等于被染白的格子数。
  • 对于棋盘的每一列,被染黑的格子数等于被染白的格子数。

请输出任意一种染色方案,如果无解,输出 \(-1\)

本题有多组测试数据,\(1 \leq T \leq 10^{4}\)\(2 \leq n,m \leq 500\)\(\sum (n \times m) \leq 2.5 \times 10^{5}\)

发现横竖之间没有影响,所以分开考虑。

考虑只有竖着,那么横向黑白染色,这无法影响道下一行,所以忽略。

纵向类似即可。

代码:https://codeforces.com/problemset/submission/1863/225041894

E. Speedrun

你在玩一个游戏,要完成 \(n\) 个任务。其中对于每个任务 \(i\),它只能在某一天的第 \(h_i\) 时刻完成。游戏每天有 \(k\) 个小时,分别编号为 \(0,1,...k-1\)

给出 \(m\) 对任务间的依赖关系,\((a_i,b_i)\) 表示 \(a_i\) 必须比 \(b_i\) 先完成。保证依赖关系不形成环。

完成任务不需要时间,也就是说可以在同一天的同一时刻先后完成多个任务。

求完成所有任务所需的最短时间。这里的时间定义为:完成最后一个任务的时刻 与 开始第一个任务的时刻 之差。

多组数据,\(T\le 10^5\)\(\sum n,m\le 2\times 10^5\)\(k\le 10^9\)

最优的情况是延迟了一部分拓扑序第一的点,而且这一部分一定是前缀。

所以扫一次前缀,一一延迟更新当前答案,然后更新总答案。

每一个点至多更新一次,所以这部分 \(O(n)\)

代码:https://codeforces.com/problemset/submission/1863/225021336

F. Divide, XOR, and Conquer

有一个长为 \(n\) 的数组 \(a_1, a_2, \cdots, a_n\)

在每次操作中,你可以把数组分成两段,留下一段,扔掉另一段,要求前者的异或和不小于后者的。重复操作,直到只剩下一个数为止。

对于每个 \(i\),问最后剩下来的可不可能是第 \(i\) 个数。

\(t\) 组数据。\(1 \le t \le 10\ 000\)\(1 \le n \le 10\ 000\)\(1 \le a_i \le 2^{60}\)\(\sum n \le 10\ 000\)

有一个显然的 \(O(n^3)\) 做法。

考虑一个区间 \([l, r]\) 什么时候可以被转移过来,由于异或,从二进制入手。

假定从 \([l, k]\) 转移过来,其区间异或和为 \(x\)\([l, r]\) 区间异或和为 \(y\)

如果 \(x\) 的第 \(k\) 位为 \(0\),那么显然两边这一位都是相等的。如果为 \(1\),那么有一边会大一点,下面的位随意了。

所以可以有条件 \(y \& \mathrm{highbit}(x) \ne 0\) 则可以转移。

于是一个一个长度递减做下去即可。

代码:https://codeforces.com/problemset/submission/1863/225050040

G. Swaps

给定长度为 \(n\) 的序列 \(a\),每次操作可以选定一个 \(i\),并 \(\operatorname{swap}(a_i,a_{a_i})\)。求能通过某种操作顺序得到的不同序列数。

\(n\le 10^6\)

简洁的题面,深邃的思想。

首先,一个经典的套路是:

对于序列中涉及到对于 \(a_i\)​​ 和 \(a_{a_i}\)​ 进行操作的问题,一般可以考虑建立 \((i,a_i​)\) 的内向基环树或者 \((a_i​,i)\) 的外向基环树转化为图论问题。

-- from weakpyt

一次交换相当于使得一个点自环,儿子连向父亲。

于是转换为对于一个点,儿子可以断一条边,并且至多段一条边的模型。

所以如果只是一棵树的话,答案就是 \(\prod (d_x + 1)\)

然而有环,发现环上所有边的断掉的情况不存在。

再发现环上留一条边不断,但是每一个点都断了一条边/或者不变的情况都是一样的,这部分显然是 \(\sum (d_x - 1 + 1)\) 的。

所以减去重复的,只保留一个,答案为:

\[\prod_{cycles}(\prod_{x \in cycle} (d_x + 1) - 1 - (-1 + \sum d_x)) \prod_{x \not \in cycle} (d_x + 1) \]

化简一下:

\[\prod_{cycles}(\prod_{x \in cycle} (d_x + 1)- \sum d_x) \prod_{x \not \in cycle} (d_x + 1) \]

这样就好求了。

代码:https://codeforces.com/problemset/submission/1863/225037149

H. Goldberg Machine

给定一棵树,每个节点要么没有儿子,要么有两个儿子,每个叶子节点有一个权值。

多次修改某个叶子节点的权值,维护递推式子:\(f_x = 2 \max(f_y, f_z) - (f_y \ne f_z)\)

\(t_x = f_x - 1\),则递推式子转换为 \(t_x = 2 \max(t_y, t_z) + [t_y = y_z]\)

\(x\) 的深度为 \(dep_x\),则可以令叶子 \(g_x = 2^{dep_x} f_x\),则递推式子为 \(g_x = \max(g_y, g_z) + 2^{dep_x}[g_y = g_z]\)

有一个结论是 \(g_x\) 的二进制中 \(1\) 的个数是 \(\log A + \log n\) 级别的。

考虑暴力合并。

假定 \(x, y\)\(g\) 相等,则可以在 \(z = \mathrm{LCA}(x, y)\) 处贡献 \(2^{dep_z}\)

于是可以利用 vector 字典序暴力找相同的,然后合并即可。

最后会得到很多个答案,取最大的即可。

为什么取最大的正确性没问题?考虑如果 \(x\) 在和 \(y\) 之前与某一个 \(u\) 合并了,那么合并的位置一定在 \(z\) 下面,也就是贡献 \(2^{dep}\) 一定大于 \(2^{dep_x}\),使得最终的答案大于错误的答案,所以如此是没有问题的。

由于当日晚上呕吐,身体不适,所以没有写本题。然而代码实际上是好写的,不过多赘述。

1753

成功因为虚拟机炸了,重新写一遍此文。

都是没有保存的错

A. Make Nonzero Sum

由于 Note that it is not required to minimize the number of segments in the partition.。考虑每一段最小化……

可以发现,每一段都可以划分为长度为 1 或 2 的段。于是考虑影响。

只有长度为 2 的段会改变正负,不妨令 \(C_+, C_-\) 分别表示 1 和 -1 的个数,并假定 1 更多。

不难发现,只需要 \(\frac {|C_+ - C_-|}2\) 个长度为 2 的即可。

如果不是整数,那么直接判不可以即可。

由于有影响,考虑 DP。

\(f_i\) 表示考虑前 \(i\) 个数,最多能够放多少个长度为 2 的。

于是有

\[f_i = \max \begin{cases} f_{i - 1} \\ f_{i - 2} + 1 &, a_i = 1 \end{cases} \]

考虑在 DP 变化的地方放置长度为 2 的即可。

B. Factorial Divisibility

当时脑子抽了,用了两种合并的方法。

详见:https://codeforces.com/contest/1753/submission/211561532

但是实际上只需要通过 \(x! = x \times (x -1)!\) 合成即可(2048……

C. Wish I Knew How to Sort

假定有 \(C_0\)\(0\),并且在前 \(C_0\) 个数中有 \(k\) 个 1。

那么考虑此时一个有效的操作,即是在前 \(C_0\) 中选择到了一个 \(1\),在后面中选择了一个 \(0\)

有效的概率为

\[P_k = \cfrac {k^2}{n \choose 2} \]

于是考虑状态转移,设 \(f_k\) 表示从前 \(C_0\) 个数中有 \(k\)\(1\) 的状态转移到 \(0\)\(1\) 的期望步数。

根据 markov 中的期望线性方程求解的方法,有

\[f_k = 1 + (1 - P_k)f_k + P_k f_{k - 1} \]

稍微魔改一下,就变成了:

\[f_k = \frac {1}{P_k} + f_{k - 1} \]

于是小小递推即可。

然而我当时是反着推的,无所谓,一样的:Submission #211560140 - Codeforces

D. The Beach

转换问题:等价于将两个 . 移动到一起的最小代价。

显然可以发现,一个障碍最多移动一次。

借用大佬的图:

于是我们可以考虑如此建图。跑一个最短路即可。

提交:Submission #211566195 - Codeforces

E. N Machines

非常恶心,虽然不是顶级难度。

最优的策略一定是把乘法向后移,把加法向前移。

思考 It's guaranteed that the current value of the resulting product does not exceed 2x10^9. 的意义。

发现,除去 \(\times 1\),最多只会有 \(\log C\) 个乘法。

于是考虑枚举其子集,为 \(2^{\log C}\)。所以需要优化。

有一个简单而优雅的剪枝:如果两个数相等,那么一定是选择最前面的。

由于 \(12! = 6227020800 \gt 2 \times 10^9\),所以其实最多只会有 \(O(2^{12})\) 种状态。

那么在钦定了向后移动的乘法后,我们需要找到前 \(rest\) 个移动到前面贡献最大的加法。

考虑二分移动到前面的贡献 \(\Delta\),在每一段再二分数量。

考虑如何计算每一个加法的 \(\Delta\) ?考虑加法移动前,其贡献为 \(x \times suf_x\),移动后的贡献为 \(x \times pre_x \times suf_x\)

其中 \(suf_x\)\(pre_x\) 是指乘法移动后,\(x\) 前面的乘法前缀积和后面的乘法后缀积。

于是 \(\Delta x = x \times (pre_x - 1) \times suf_x\)

NOTICE

  • 二分 \(\Delta\) 时找到最大的 \(cnt > rest\) 的那个 \(\Delta\),由于多算了 \(cnt- rest\) 个,并且这些数的贡献一定是 \(\Delta\),所以再减去 \((cnt - rest) \times \Delta\) 即可。

  • \(\Delta\) 可能很大很大,所以上界大一点(我用的倍增,所以直接是从 \(2^{60}\) 开始向下……虽然没必要)

提交:Submission #211609810 - Codeforces

F. Minecraft Series

首先固定一个正方形,考虑贡献:将数分为正数与负数,分别计算 \(mex_p\)\(mex_n\)

正的为 positive,负的为 negative

于是贡献为 \(mex_p + mex_n - 1\)

由于 \(mex\) 的单调性,发现包括合法正方形的正方形一定合法,所以考虑双指针维护所在最小合法正方形的。

注意,是在每一条对角线上来一发双指针,这样才能保证复杂度。

然后,然后就搞定了。

可以优化的是,\(mex\) 可以利用分块优化复杂度。

于是你可以得到一个复杂度为:

\[O(nm \cdot \min\{n, m\} + n m \sqrt k) \]

的优雅 brute force……

提交:https://codeforces.com/contest/1753/submission/211685792

然而……不断的 TLE 让我怀疑人生,最后发现……

参考:讨论

1718

A. Burenka and Traditions (hard version)

\(T\) 组数据,对于每一组数据,你有一个长度为 \(n\) 的数组 \(a\),每一次操作可以选择一段区间 \([l,r]\),花费 \(\left \lceil \dfrac{r-l+1}{2} \right \rceil\) 秒使区间内的数都异或 \(x\),问最少需要几秒才能把数组中所有的元素都变成零。

首先不难发现有一个非常简单的上界 \(n\),也就是每两个两个的变成 \(0\) 即可,或者换成一个一个向后推的过程。

然而如果存在一个区间本身异或和为 \(0\),那么发现左端点是没有必要推的,这使得操作次数 \(-1\)。发现这优化十分显然,于是利用 set 维护最小的段即可。

代码:Easy: https://codeforces.com/problemset/submission/1718/229358204, Hard: https://codeforces.com/problemset/submission/1718/229358185

B. Fibonacci Strings

给你一个数列 \(\{c_k\}\),可以执行若干轮操作(轮数由你决定)。对于第 \(i\) 轮操作:

  • 选定一个 \([1,k]\) 范围内的整数 \(d_i\)。当 \(i \ge 2\) 时,必须保证 \(d_i \neq d_{i-1}\)

  • \(c_{d_i}\) 减去 \(f_i\),其中 \(f_i\) 是斐波那契数列(\(1,1,2,3,5,8,13,\ldots\))的第 \(i\) 项。

问:你能否让 \(c_1\)\(c_k\) 全为 \(0\)

呃呃,原题不是这样的,但是既然这么翻译了,那么贪心的模拟一下即可。

代码:https://codeforces.com/problemset/submission/1718/229357931

C. Tonya and Burenka-179

给定一个长度为 \(n\) 的序列,要求求出一个权值最大的对 \((p, k)\),其中 \(0 \le p, k \lt n\)

定义一个对 \((p, k)\) 的权值为 \(\sum_{i = 1}^{n} A_{p + k i \bmod n}\)

先考虑最朴素的做法 \(O(n^2)\),发现,考虑优化其过程,发现可以类似于分治,例如 \((p, k)\) 可以由 \((p, 2k)\)\((p + k, 2k)\) 合并而来。

但是发现 \((p, k)\) 一定不必 \(max((p, 2k), (p + k, 2k))\) 更优,所以此时 \(k\) 是不必要的。

于是发现 \(k\) 是最优的当且仅当 \(\frac nk\) 为质数,这只有 \(6\) 个,每一个用一个 set 维护即可,这是 \(O(6 n \log n)\) 的。

代码:https://codeforces.com/problemset/submission/1718/229362201

D. Permutation for Burenka

给定一个排列 \(p\) 和有 \(k\) 个空位的序列 \(a\),已经确定了可以 \(k - 1\) 个数,每次询问给定一个数,要求是否可以将这 \(k\) 个数填入 \(a\) 中使得 \(\forall i < j, \arg \max p_{[i, j]} = \arg \max a_{[i, j]}\)

发现这个限制可以转化为两者的笛卡尔树同构,发现排列的笛卡尔树是确定的,先构出来,然后考虑 \(a\)

发现每一个空位都可以填的数是一个区间,而剩下一个数合法也一定是一个区间,于是考虑如何求上下界。

首先将每一个位置的上下界求出来,考虑一个十分经典的贪心来求它,按照区间右端点从大到小排序,尽量选择大的来满足它,那么到第一个不可以填的区间的时候,就意味着剩下的一个数必须大于这个区间的左端点了,于是可以求出下界了。

同理,按照左端点从小到大排序,可以求出其上界。

不过需要注意,如果遇到了两个没有办法满足的区间的时候,无论填什么都不可以了,此时所有询问回答皆为 NO

代码:https://codeforces.com/problemset/submission/1718/229374552

E. Impressionism

Burenka 有两张图片 \(a\)\(b\) ,它们的大小可以表示为 \(n \times m\) 的像素组合。每幅画的每个像素都有一个颜色——表示为一个从 \(0\)\(2 \times 10^5\) 的数字,并且在两幅画的每一行或每一列中都没有重复的颜色,除了颜色 \(0\)

Burenka 想把图片 \(a\) 变成图片 \(b\)。为了实现她的目标,Burenka 可以执行 \(2\) 操作之一:交换 \(a\) 的任意两行或其任意两列。现在需要你来告诉 Burenka 该如何操作,或者说明其不可能完成。

模拟 \(\mathrm{Pity Problem}\),利用二分图一一匹配即可。

F. Burenka, an Array and Queries

每次询问一个区间,求 \(\prod a_i\)\(1 \sim C\) 中互质的数的个数。

有根号分治,或者乱搞。

但是官方题解所说:The only one hint to this problem is don't try to solve, it's not worth it.

1710

B. Rain

给定一个 \(n\) ,这 \(n\) 天会降雨,每一个降雨天有一个 \(x_i\) 和一个 \(p_i\) ,表示以 \(x_i\) 为中心,降雨量向左右两边递减,即对于所有的数轴上的点 \(x\) ,其降雨量都会增加 \(max(0,p_i−∣x_i−x∣)\)

现在你可以消除一天的降雨,问消除第 \(i\) 天的降雨是否可以使得没有任何地方的降雨大于 \(m\)

考虑整个图长什么样子,发现峰值(很多个)一定是某个 \(x_i\) 上。

于是求出每一个 \(x_i\) 对应的降雨 \(h_i\),这可以通过二分和差分很容易的求出(考虑每一次增加的是一个一次函数,这可以通过 \(k, b\) 简单的维护)

于是考虑对于删除一个后 \(m\) 的限制。

如果 \(h_i \le m\),自然不需要关注,删除一个 \(k\) 之后 \(h_i \to h_i - \max(0, p_k - |x_k - x_i|)\)

我们需要 \(h_i - \max(0, p_k - |x_k - x_i|) \le m\) 也就是 \(h - (p_k - |x_k - x_i|) \le m\),考虑原本 \(h_i > m\),如果后者不满足,那么必定不满足。

于是就是 \(h_i - p_k \le m + |x_k - x_i|\),考虑绝对值又是 \(\max(x_k - x_i, x_i - x_k)\),于是两边同时都需要满足,也就是:

\[\begin{cases} h_i + x_i \le m + x_k + p_k \\ h_i - x_i \le m - x_k + p_k \end{cases} \]

分别记录 \(h_i + x_i\)\(h_i - x_i\) 的最大值即可判断 \(k\) 删除后是否满足条件。

代码(我在乱搞……所以代码有些抽象):https://codeforces.com/problemset/submission/1710/229413132

C. XOR Triangle

给你一个数 \(n\),问:有多少对数 \(0\leq a,b,c \leq n\) 满足 \(a \oplus b,b \oplus c,a \oplus c\) 。三个数字构成了一个非退化三角形,也就是两条短边之和大于第三边的长度。\(\oplus\) 表示二进制下的异或操作。

首先,很难发现对于所有数位,如果 \(a \oplus b + b \oplus c > a \oplus c\),那么就满足 \(x \oplus y + y \oplus z > x \oplus z\)。其余两个限制同理。

于是考虑数位 DP,压位判断是否满足三个条件即可。

代码:https://codeforces.com/contest/1710/submission/229415904

D. Recover the Tree

你需要根据题目给出的信息构造出一棵树,满足如下条件:

  1. 树的节点个数为 \(n\)
  2. 对于每个区间 \([l,r]\) 给出是或不是连通块。

数据保证有解,\(n\leqslant 2000\)

首先满足小的区间是最优的,考虑如何满足大的区间。

考虑合并 \(i, j\),那么此时的联通块大概是这样的:

按照上面的连边即可,注意是连到 \(i\)\(j\),而不是 \(i, j\) 所在连通块的某一个点,中间的块随意,利用并查集维护即可。

代码:https://codeforces.com/contest/1710/submission/229423482

E. Two Arrays

现有两个整数数组 \(a_1, a_2, \dots, a_n\)\(b_1, b_2, \dots, b_m\)

Alice 和 Bob 将要玩一个游戏,Alice 先手,然后他们轮流进行操作。

他们在一个 \(n\times m\) 的网格上进行游戏(网格有 \(n\)\(m\) 列)。刚开始,有一个棋子放在网格的一排一列上。

在 Alice 或 Bob 轮次中,玩家可以选择以下两个动作中的一个进行操作:

  1. 将棋子移动到一个不同的格子上,该格子必须和棋子的原位置在同排或者同列上。玩家不能将棋子移动到已经被访问过 \(1000\) 次的格子上(也就是说,在游戏过程中,棋子最多可以在某个格子停留 \(1000\) 次)。请注意,我们规定起始单元格在开始时被视作访问过一次。
  2. \(a_r + b_c\) 的得分立刻结束游戏,\((r, c)\) 表示棋子当前所在的单元格(也就是说,棋子在第 \(r\) 排第 \(c\) 列上)。

Bob 想要最大化自己的得分,Alice 则想要最小化自己的得分。如果他们都以最佳方式玩这个游戏,则最终的得分是多少?

其实发现 \(1000\) 次和 \(1\) 次没有区别,直接忽略。

首先,我们知道博弈双方足够聪明,可以直接知道比赛结果 \(res\),那么意味着 Bob 只能走大于 \(res\) 的地方,而 Alice 只能走小于等于 \(res\) 的地方。

于是可以得到一张二分图,这让我们想到经典的结论:Alice 赢的充要条件是二分图的最大匹配必须包含起点 \(S\)

但是边数是 \(O(nm)\) 的,非常难受,考虑转化思路,找二分图最大独立集,这要求每行每列都只有一边出现,我们给每个行列涂颜色。那么一个方格可以取当且仅当方格的颜色和行列所染颜色都一样。

于是对于整个图(\(a, b\))排个序,于是发现黑白大概就是如图:

枚举这个点即可,但是直接枚举是不可以接受的,这是 \(O(nm)\),但是考虑到这必定是一个凸函数,所以可以单调性优化,可以做到 \(O(n + m)\) 找。

于是加上二分的复杂度为 \(O(n \log n)\)

1707

A. Doremy's IQ

哆来咪·苏伊特参加了 \(n\) 场比赛。 比赛 \(i\) 只能在第 \(i\) 天进行。比赛 \(i\) 的难度为 \(a_i\)。最初,哆来咪的 IQ 为 \(q\) 。 在第 \(i\) 天,哆来咪将选择是否参加比赛 i。只有当她当前的 IQ 大于 \(0\) 时,她才能参加比赛。

如果哆来咪选择在第 \(i\) 天参加比赛 \(i\),则会发生以下情况:

  • 如果 \(a_i>q\),哆来咪会觉得自己不够聪明,所以 \(q\) 将会减 \(1\)
  • 否则,什么都不会改变。

如果她选择不参加比赛,一切都不会改变。哆来咪想参加尽可能多的比赛。请给哆来咪一个解决方案。

  • 简单二分,前面部分只参加 \(\le q\) 的比赛,后面部分经量参加,看是否可是使得 \(q = 0\)
  • 或者从后向前考虑,可以 \(O(n)\)

B. Difference Array

你有一个初始长度为 \(n\) 的有序数组 \(a\)(从小到大)。设 \(a\) 当前长度为 \(l\),你要对 \(a\) 作差分,即令 \(b_i = a_{i+1} - a_i(1\le i < l)\),然后将 \(b\) 数组从小到大排序,接着让 \(a_i = b_i(1 \le i < l)\),并继续执行上述操作。

显然,每一次操作后 \(a\) 数组的长度都会减少 \(1\);执行 \(n - 1\) 次操作之后,\(a\) 中只会剩下一个元素,请你输出这个剩下的元素。

首先有个不难发现的是相同的数,只需要有一个贡献即可。

然后发现会有 \(O(\sqrt S)\) 个本质不同的数,也就是说,至多需要删 \(O(\sqrt S)\) 次,每次删一个的代价是 \(O(n \log n)\),于是你会发现这跑的飞快。

因为这复杂度是 \(O(S \log n)\) 而不是根号的。考虑利用构造证明,如果需要每一次都只减少 \(1\) 个值,而不产生相同的值,那么最优秀的显然是 \(f(x) = 2^x\),因为存在 \(\Delta f(x) = f(x - 1)\),于是这种东西至多是 \(O(\log S)\) 个的,所以复杂度不会高于 \(O(n \log S)\),然而存在神秘证明,操作次数是 \(O(\frac S n)\) 的,所以复杂度是 \(O(S \log n)\) 的,这看题解即可。

C. DFS Trees

有一图有\(n\)个点\(m\)条边。第\(i\)条边的权值是\(i\)
现在有一个错误的最小生成树算法(就是有bug)

vis := an array of length n
s := a set of edges

function dfs(u):
    vis[u] := true
    iterate through each edge (u, v) in the order from smallest to largest edge weight
        if vis[v] = false
            add edge (u, v) into the set (s)
            dfs(v)

function findMST(u):
    reset all elements of (vis) to false
    reset the edge set (s) to empty
    dfs(u)
    return the edge set (s)

每次调用\(findMST(i)\)时,会返回这个图的最小生成树,你要判定那些是正确的最小生成树。

首先,最小生成树是唯一的,于是整张图会变成一棵树加一些边。

在 DFS Tree 里面,只有返祖边,我们考虑每一天非树边在什么时候满足为反祖边。

如果 \((x, y)\) 不为祖先关系,那么是各自子树内即可。树上差分即可。

D. Partial Virtual Trees

给定 \(n\) 个点的树以及质数 \(p\),对每个 \(k=1,2,\cdots,n-1\) 计算满足下述条件的点集序列 \(\{S_i\}_{i=0}^k\) 数量 \(\bmod\ p\)

  • \(\{1\}=S_k\subsetneq S_{k-1}\subsetneq\cdots\subsetneq S_0=\{1,2,\cdots,n\}\)
  • 对每个 \(S_i\) 以及 \(u,v\in S_i\),都有 \(\text{LCA}(u,v)\in S_i\)

其中 \(\text{LCA}(u,v)\) 表示以 \(1\) 为根时 \(u\)\(v\) 的最近公共祖先。

真子集很恼火,于是利用容斥搞掉。

逆着删元素,于是 \(f_{x, i}\) 表示 \(x\)\(i\) 时被删除,初始全部点亮。

于是儿子必须全部消失或只剩下一个,\(f_{x, i}\) 才能消失,转移参考 https://www.luogu.com.cn/blog/_post/454338 即可。

1685

A. Circular Local MiniMax

检查是否存在对于 \(a_1, a_2, \cdots, a_n\) 的重新排列,使得 \(i\)\(1\)\(n\) 中至少有一个以下条件成立。

  • \(a_{i-1} < a_i > a_{i+1}\)
  • \(a_{i-1} > a_i < a_{i+1}\)

首先奇数长度一定不可以,于是只用考虑偶数。

此时只需要分成两个部分,交错放置,然后判断即可。

B. Linguistics

Alina 发现了一种只由 \(\text{A, B, AB, BA}\) 四种单词组成的语言,这种语言不含有空格,书写句子时只需要将单词直接连接起来即可。

她很好奇是否可以用 \(a\)\(\text{A}\)\(b\)\(\text{B}\)\(c\)\(\text{AB}\)\(d\)\(\text{BA}\) 拼接形成句子 \(s\)

换句话说,是否可以用 \(a+b+c+d\) 个单词以某种顺序拼接出句子 \(s\),这 \(a+b+c+d\) 个单词都得被用到,他们的顺序可以由你决定。

很抽象的贪心。考虑先把形如 \(XYXYX...\) 的段都提出来,按照长度排个序。

首先如果长度为偶数,那么优先满足 \(XY\) 的。在满足了所有的偶数之后,我们继续考虑奇数的,此时发现,两者可以满足的数量相加是恒定的,所以可以任意满足。

最后剩下了一点偶数的,那么贪心的放即可。

C. Bring Balance

Alina 有一个长度为 \(2n\) 的括号序列 \(s\),她想把这个括号序列变成一个合法的括号序列。每一次操作可以 reverse \(s\) 的任意子串,求最小操作次数。

经典的画折线,发现至多需要两次,也就是翻转至高点左右两侧。

考虑什么时候只用翻转一次,找到至少翻转的那个区间 \([l, r]\),找到左右两部分最高的点 \(L, R\),如果 \(\forall i \in [l, r], h_i \le h_L + h_R\),那么可以只用一次,正确性显然。

D. Permutation Weight

给定一个 \(1\sim n\) 的排列 \(p\)\(n \le 200\)
对于一个 \(1\sim n\) 的排列 \(q\),定义其权值为:

\[|q_1-p_{q_2}|+|q_2-p_{q_3}|+|q_3-p_{q_4}|+\cdots+|q_{n-1}-p_{q_n}|+|q_n-p_{q_1}| \]

找出 任意一个 权值最小化的 \(1\sim n\) 的排列 \(q\)
Hard Version 是找到字典序最小的。

先考虑简单版的怎么做。

\(f = p^{-1}\),先不考虑 \(q\) 是否是一个排列,那么存在 \(q_i = p_{q_{i + 1}}\),两边同时套上 \(f\) 得到 \(f_{q_i} = q_{i + 1}\)

于是,可以钦定 \(q_1 = 1\),于是可以推出 \(q\) 的样子。

然而发现 \(q\) 存在多个环,推不出来,所以需要交换某些东西,使得只存在一个环。为了达到下界,我们只能交换相邻的 \(f_i, f_{i + 1}\),保证损失最小。

利用并查集维护可以做到 \(O(n)\)

然而对于字典序最小,看到数据范围容易想到,每位钦定的选择某一个值,判断这个前缀是否可行,可以做到 \(O(n^3)\)

我们重新看简单版的过程,我们有很多 \(q_i \to f_{q_{i + 1}}\),考虑得到了一些 \((i, f_i)\)\(q_i\) 则规定了其顺序,而答案则是 \(\sum (q_i, f_{q_i})[0] - (q_{i - 1}, f_{q_{i - 1}})[1]\)

于是我们根据 \(f_i\) 可以划分出一些环,发现在这些环内跳是没有代价的,这十分优秀。

现在转而考虑 \(f_{q_{i - 1}} \to q_i\) 的这条边,发现需要经量使得两者接近,并且所有连完之后满足:

  • 所有边只形成一个环。
  • 使得所有 \(f_i\) 划分出来的环联通。

而为了使得答案最优秀,我们需要:

  • 每个边不会重复合并划分出来的环。
  • \(f_{q_{i - 1}} \to q_i\) 形成的图中,每个环编号都是连续的,且可以被拆分为递增和递减的两个段。

此时我们需要判断一个前缀是否合法/优秀,于是就可以采用如下方法:

  • 不存在两条单增链相交,不存在两条单减链相交(自环同时算作单增链及单减链)。
  • 不存在未连边的点同时被单增链及单减链覆盖。
  • 不存在被覆盖的某边 \((i, i + 1)\) 在同一个划分的环内。
  • 剩下的所有作为边界的 \((i, i + 1)\) 可以使得所有颜色联通。

这可以利用差分 + 并查集每次 \(O(n)\) 的维护。

于是总复杂度为 \(O(n^3)\)

GYM 103495

这里挑选部分值得一谈的题。

B. Among Us

给出一张带边权的无向图,边权可被视为长度。最开始有 \(2\) 个内鬼和至多 \(8\) 个船员,内鬼起始位置给出,内鬼只能沿着边走。内鬼知道一系列形如“船员 \(p\) 会在第 \(t\) 秒出现在顶点 \(x\) 的信息。若内鬼与船员在同一时间和同一地点出现,则 内鬼可以把船员给砍了。内鬼只能在前面给出的时间/地点砍人。你需要为 \(2\) 个内鬼分别规划路径使得它们能够尽快将所有船员都给砍了。若方案存在则输出最短时间,否则输出 \(−1\)

核心:状压,最短路,DP。

首先利用状压将两个内鬼分开,于是问题简化为对于一个人。

不难想出一个状态,设 \(f_{x, t, S}\) 表示是否能够在杀了 \(S\) 中的人后在 \(t\) 时到 \(x\)

如果固定 \(x, S\),发现对于一个后缀 \(t\) 都生效,那么可以将 \(t\) 作为值,于是状态为 \(f_{x, S}\) 表示杀了 \(S\) 中的人并到达 \(x\) 的最短时间。

接下来转移有两种:

  • \(\to f_{y, S}\),也就是移动到 \(y\)
  • \(\to f_{x, S | 2^k}\),也就是在 \(x\) 蹲守某个人。

类似 djk 的跑即可。

D. Pattern Lock

给定 \(n\)\(m\) 列的点阵图,用一条折线经过所有的点各一次,要求每条线段不经过除端点外的其他点,且形成的角都是锐角。

对于 \(n, m\) 存在偶数的情况是简单的。

这样两行两行的构造即可。

对于都有奇数的,那么先构造一个 \(3 \times 3\) 的,接下来会分出两个偶数矩阵即可。

大概就是

E. Stone Ocean

定义一个长为 \(n\) 串的权重 \(w(s)\) 为有多少个排列 \(p\) 使得 \(s[p_1]s[p_2] \ldots s[p_n]\) 是一个回文,现在有 \(n \le 30\) 个串,从每个串随机选一个位置的字符,连接成一个长为 \(n\) 的新串,求这个新串的 \(w\) 的期望。

先考虑如何计算 \(w(s)\)。先判断是否能够成为回文,如果可以,枚举哪两个会配对,最后乘上 \((\frac n2)!\) 来修正这些配对的位置即可。

于是类似的,枚举哪两个字符串会配对,记 \(mat(i, j)\) 表示 \(s_i, s_j\) 选择相同字符的方案数。那么总贡献即是 \((\frac n2)! 2^{\frac n2} \prod mat_{i, j}\) 其中 \(2^{\frac n2}\) 是选择一个子集作为左部,\(\prod\) 内的东西是所有配对的对。注意在奇数的情况下需要新建一个虚点 \(x\) 使得 \(mat_{i, x} = |s_i|\),与虚点匹配的放在最中间,还要注意这个虚点不会影响前面的系数。

考虑 \(n\) 很小,进行状压,\(f[S] \times mat_{i, j} \to f[S | 2^i | 2^j]\),这是容易理解的。最后除以方案数即可得出期望。为了不重复贡献,每次 \(i\) 只需要设为最小的即可。

乍一看是 \(2^{30}\) 的状态数,然而实际上远远没有这么恐怖,由于我们每次选择了最小的 \(i\),对于状态,必须满足前缀 \(1\) 的个数 \(\ge 1\) 的个数的一半,于是状态数大概为:

\[\sum_{i = 0}^{\frac n2} \binom{n - i}{i} \]

\(n = 30\)\(= 1346269\)(实际也是如此),利用类似队列的思路转移,那么只需要 \(\times 30\),计算级别在 \(4 \times 10^7\),能过。

题解状态数分析就是一坨,不好评价。

F. Jumping Monkey II

对每个点 \(x\),以 \(x\) 为起点出发时,求所有简单路径的 LIS,注意 \(x\) 必选。

首先容易得出一个 \(O(n^3 \log n)\) 的解法,也就是 \(O(n^2)\) 的枚举路径,然后 \(O(n \log n)\) 的求 LIS

其次,枚举每一个根 \(rt\),设 \(f_{x, i}\) 表示以 \(i\) 开头的 LIS 的最长长度,这容易利用线段树合并完成 \(O(n^2 \log n)\)

发现这是 \(O(n^2)\) 树上状态问题,考虑分治。这里的话边分治更简单,并且常数很小。

只是注意这里边分治需要在三度化的时候将点权下放到边权上:

最终复杂度 \(O(n \log^2 n)\)

G. Five Phases

给定一个 \(5\) 元环,需要进行 \(k \le 10^5\) 次操作,每次操作可以进入如下操作之一,求到达目标局面的方案数。

  • 单点 \(\pm 1\) 或者全局 \(\pm 1\)
  • 相邻的 \(3\)\(\pm 1\)
  • 相邻的 \(2\)\(\pm 1\),对面的那个 \(\mp 1\)

联想到生成函数,是 \(5\) 元的:

\[[x^a y^b z^c w^d v^e] \left( \begin{aligned} & x + y + z + w + v + \frac 1x + \frac 1y + \frac 1z + \frac 1 w + \frac 1 v \\ & xyzwv + \frac 1 {xyzwb} \\ & xyz + yzw + zwv + wvx + vxy + \frac 1 {xyz} + \frac 1 {yzw} + \frac 1 {zwv} + \frac 1 {wvx} + \frac 1 {vxy} \\ & \frac {xy}{w} + \frac {yz}{v} + \frac {zw}{x} + \frac {wv}{y} + \frac {vx}{z}+ \frac {w}{xy} + \frac {v}{yz} + \frac {x}{zw} + \frac {y}{wv} + \frac {z}{vx} \end{aligned} \right)^k \]

经过通分化简,可以得到:

\[[x^a y^b z^c w^d v^e] \left( \frac {(1 + xy)(1 + yz)(1 + zw)(1 + wv)(1 + vx)}{xyzwv} \right)^k \]

\(\frac 1 {xyzwv}\) 提出去,得到:

\[[x^{a + k} y^{b + k} z^{c + k} w^{d + k} v^{e + k}] \left( {(1 + xy)(1 + yz)(1 + zw)(1 + wv)(1 + vx)} \right)^k \]

先考虑一个简化的问题:\([x^a y^b z^c]((1 + xy)(1 + yz)(1 + zx))^k\)

考虑有哪些组合 \((xy)^l (yz)^m (zx)^n\) 可以贡献到目标,列出等式:

\[\begin{cases} a = l + n \\ b = l + m \\ c = m + n \end{cases} \]

发现 \(l, m,n\) 都是唯一的,类似的推广,也就变成了 \(5\) 个组合数相乘即可。

H. Reverse the String

给定字符串 \(S\),至多可以翻转一个区间,求最小字典序。

首先发现翻转的开头是一定的,也就是第一个存在 \(S_j \lt S_i\) 的那个 \(i\)

之后也就只有 \(O(n)\) 种可能,利用 hash \(+\) 二分比较字典序即可。

L. Tree Game

给一棵树,每个点有权值,权值是一个排列。从叶子开始,每次重新排列 \(x\) 和其所有儿子,然后向上递归。目标权值等于结点编号,给定其中一些权值,问有多少可能的权值排列可以排序成功。

首先考虑全部确定的情况,发现只需要不断交换模拟即可。

而加入 \(0\) 之后呢,发现判断还是只需要模拟即可,只是 \(0\) 是万金油,可以等于一切。

于是呢,考虑当前节点 \(x\),现在可以重排一些东西,和一些 \(0\),发现其实这些 \(0\) 任意排列都可以,也就是可以贡献一个 \(cnt!\)。而又无法影响到子树内部,所以可以得到递推式:

\[f_x = cnt! \prod f_y \]

随便做即可。

GYM 103743

B.Prime Ring Plus

\(1 ∼ n\) 分成若干个环,每个环上相邻两数之和是质数,\(n \le 10^4\)

\(O(n^2)\) 的枚举可以放在一起的,发现奇偶形成二分图,那么跑一个网络流即可,注意一个需要连两个。

复杂度 \(O(n \sqrt {n^2}) = O(n^2)\)

D. Finding Pairs

给定一个序列和一个数 \(k\),每次询问一个区间,问在区间中找若干对不含重复元素的距离为 \(k\) 的数的最大权值和。

\(\bmod k\) 相同的弄出来,可以作为一个单独的问题。

如果是暴力,自然想到设 \(f_{i, 0/1}\) 表示考虑了前 \(i\) 个数,最后一个数选没选的最大价值。

于是考虑可以莫队,但是回滚,设 \(f_{i, 0/1, 0/1}\) 表示 \(\bmod k\)\(i\) 的序列的 DP 数组,那么稍微特判一个只有一个/两个数的情况转移即可。

复杂度 \(O(n \sqrt n)\)

E.Playing Cards

给定序列 \(A, B\),以及一个 \(k \le 10^9\),构造一个排列 \(P\),使得下式最小:

\[\sum_{i = 1}^n \left\lceil \frac {\max(0, B_i - A_{P_i})}{k} \right\rceil \]

有一个不是那么优秀的做法,每次取出最小的 \(A_i\),如果存在比 \(A_i\) 小的 \(B_i\),贪心匹配 即可,否则将 \(A_i \leftarrow A_i + k\),并 \(ans \leftarrow ans + 1\),将 \(A_i\) 重新放入堆中,这样是 \(O(n^2 \log n)\) 的。

注意这似乎不太好优化,我们将对于 \(A_i\)\(+ k\) 变为对于 \(B_i\)\(-k\),那么做法变为从大到小枚举 \(A_i\),如果存在 \(B_i \gt A_i\),那么不断 \(B_i \leftarrow B_i - k, ans \leftarrow ans + 1\),直到所有 \(B_i \le A_i\),此时 \(A_i\) 与最大的 \(B_i\) 配对即可。

利用线段树上二分即可优化为 \(O(n \log n)\)

F. Pockets

\(n\) 种物品价值 \(v_i\),体积 \(w_i\),无限个,总容量 \(k\)
如果购买 \(i\) 个物品,则总容量变为 \(i + k\)
至多购买 \(m\) 个物品,求所有合法购买方案的价值之和,定义一个方案的价值为 \(\prod v_i\)

对于多项式还是不会……考虑单次购买的生成函数:\(f(x) = \sum v_i x^{w_i}\)

于是答案为:\(\sum_{i = 0}^m \sum_{j = 0}^{i + k} [x^j] f^i (x)\)

注意到后面是生成函数前缀和可以转化为:\(\sum_{i = 0}^m [x^{i + k}] f^i(x) \frac 1 {1 - x}\)

然而这个 \([x^{i + k}]\) 很难处理,考虑将系数平移一下:

\[[x^{m + k}] \sum_{i = 0}^m f^i(x) \frac {x^{m - i}} {1 - x} \]

然后可以将 \(f^i(x)\) 转化为 \(f^{m - i}(x)\) 的形式:

\[[x^{m + k}] \frac {f^m(x)}{1 - x} \sum_{i = 0}^m \frac {x^{m - i}}{f^{m - i}(x)} \]

后者可以利用 \(\frac {1 - x^{k + 1}}{1 - x} = \sum_{i = 0}^k x^i\) 的形式化简:

\[[x^{m + k}] \frac {f^m(x)}{1 - x} \frac {1 - \cfrac {x^{m + 1}}{f^{m + 1}(x)}}{1 - \cfrac x {f(x)}} \]

再稍微化简一下:

\[[x^{m + k}] \frac {f^{m + 1}(x) - x^{m + 1}}{(1 - x)(f(x) - x)} \]

多项式全家桶即可。

H. Super Gray Pony

求长为 \(n\)\(0/1\)\(S\)\(k\) 次格雷码后的结果,求格雷码是指将 \(S\) 看做二进制数,求其在 \(n\) 阶格雷码序列中的下标。

格雷码有个小小的性质:\(Rank(x) = x \oplus (x >> 1)\)

于是求 \(k\) 次对于前面的 \(S_{x + i}\) 来说其贡献次数为 \(\binom ki\)

利用 Lucas 来分析,只有 \(i \& k = i\) 的那些 \(S_{x + i}\) 会对于 \(S_{x}\) 做出贡献。于是对于每一个地方来一次子集卷积?

考虑 DP 的思路,设 \(f_{x, i}\) 表示对于 \(x\) 只考虑 \(k\) 的前 \(i\) 位构成的子集的贡献。

初始 \(f_{x, 0} = S_x\),考虑第 \(i\) 位,如果为 \(0\),那么不会存在新的子集,那么 \(f_{x, i} = f_{x, i - 1}\),如果为 \(1\),那么可以存在新的子集,其从 \(f_{x + 2^i, i - 1}\) 转移而来。

也就是 \(f_{x, i} = f_{x, i - 1} \oplus f_{x + 2^{i - 1}, i - 1}\)

交换一下枚举顺序,先枚举 \(i\),那么可以利用 bitset \(O(\frac {n \log n}{w})\) 的完成。

J. Balanced Tree

\(n\) 个点组成的每个节点都满足左右子树大小相差至多 \(1\) 的二叉树个数。

容易想到一个记忆化搜索的方式:

\[f_n = \begin{cases} 2 f_{\frac n2} f_{\frac n2 - 1} & \text{n is even} \\ (f_{\frac n2})^2 & \text{n is odd} \end{cases} \]

不难证明状态数是 \(2 \log n\) 的,答案一定形如 \(2^c\),可以变为指数加法。

直接记忆化复杂度是 \(O(T \log n \log \log n)\) 的,无法通过,但是可以通过分层记忆化的方式优化到 \(O(T \log n)\),只是常数略大,需要狠狠卡常才能过。

此时其实会发现每一层至多两个状态,模拟这个过程即可去掉记忆化的常数。

然而 @The_Last_Candy 给出了一种不同的方法。

将对于指数加法的式子改写为:

\[f(x) = f(\left\lfloor \frac {x - 1} 2 \right\rfloor) + f(\left\lceil \frac {x - 1} 2 \right\rceil) + [\text{x is even}] \]

发现偶数的地方会贡献一个 \(2\),那么考虑是否可以通过类似数位 DP 的方式求得所有转移时为偶数的个数。

\(f_{i, 0/1}\) 表示考虑了前 \(i\) 位,当前位为 \(0/1\) 的个数,然而由于存在 \(-1\),所以还需要增加一个 \(0/1\) 表示是否向前借位。

那么对于转移:

\[\begin{aligned} x &= n 的第 i 高位 \\ f_{i, 0, 0} &= \begin{cases} f_{i + 1, 0, 0} + 2f_{i + 1, 1, 0} & x = 0 \\ f_{i + 1, 0, 0} + 2f_{i + 1, 1, 1} & x = 1 \end{cases} \\ f_{i, 1, 0} &= \begin{cases} 0 & x = 0 \\ f_{i + 1, 0, 0} + 2 f_{i + 1, 1, 0} & x = 1 \end{cases} \\ f_{i, 1, 1} &= \begin{cases} f_{i + 1, 0, 0} + 2 f_{i + 1, 1, 1} & x = 0 \\ 0 & x = 1 \end{cases} \end{aligned} \]

反着来变成 DP 减少常数,最后指数就是 \(\sum f_{i, 0, 0}\)

GYM 104396

B. Honkai in TAIKULA

给定一张 \(n\) 个节点 \(m\) 条边的有向带权图,对每个节点,若不存在奇权圈(可经过重复顶点、重复边,若经过重复边,边权计多次),输出 Battle with the crazy Honkai,否则,输出最小奇权圈的权值(负无穷输出 Haha, stupid Honkai)。

由于需要存在圈,那么圈一定在强连通分量内,那么可以利用 tarjan 分为若干强连通子图进行求解。

考虑由于需要奇偶分开,那么拆成奇偶两个点即可。

考虑如果是跑 SPFA 的话就需要 \(O(nm^2)\) 的复杂度,显然不太能过,所以需要用到 Johnson 全源最短路算法,优化为 \(O(nm \log n)\)

注意有负权环存在的情况。

D. Rail Star

二维平面上有 \(n\) 个点,设 \(A_i,j\) 表示将第 \(i\) 个点删除后,将剩下 \(n − 1\) 个点划分为两个集合后,提取其中点数为 \(j\) 的集合,这个集合的种类数。求出该矩阵。

类似于 1860F 的想法,一共 \(O(n^2)\) 种斜率,带来 \(O(n^2)\) 种映射方式,每种映射带来的一种排序都会对于答案做出贡献。

\(O(n^2 \log n)\) 很容易维护这一个排序方式,但是我还不太清楚该如何维护答案。

E. LCM Plus GCD

输入 \(x, k\),求大小为 \(k\) 的不同的集合个数,其中所有数的 \(\gcd + \mathrm{lcm} = x\)

考虑 \(\mathrm{lcm} = k \gcd\),那么枚举 \(\gcd\) 即可得到 \(k\)

观察每一个数,将 \(k = \prod {p_i}^{c_i}\),那么对于每一个数的分解,再除以 \(\gcd\),指数需要满足 \(\min = 0, \max = c_i\)

考虑实际上因数的个数 \(\le 9\),那么考虑状压容斥,先枚举有哪些没有满足下界,在这个基础上枚举有哪些没有满足下界,复杂度 \(O(Tm2^{2m})\)

G. Moving Boxes

\(n\) 个物品在一条直线上,每个需要从 \(x_i\) 移动到 \(y_i\) ,有一个机器人移动,机器人每次只能拿一个物品,速度为 \(1\),转向需要 \(c\) 秒,最后需要回到起点,方向回到初始方向。求运输完所有物品需要的最小时间。

贪心,还不太会。

L. Architect

给出 \(n\) 个长方体,询问其是否拼接成一个 \(W \times H \times L\) 的立方体,没有重叠和空隙。

  1. 做法一,先判断体积和。将全部无交容斥为有交,数点问题即可。
  2. 做法二,利用随机化将每个立方体的体积放缩,如果满足要求,那么无论如何放缩体积都是合法的,多次随机充分 \(\to\) 必要。
  3. 做法三,还是先判断体积和,从一维结论合理外推,充要条件是每个点都覆盖了偶数次,利用 map 判断即可。

\(\downarrow 2024.03.04\)

1936

A. Bitwise Operation Wizard

交互题,每次可以询问 \(a_i | a_j\)\(a_x|a_y\) 的大小关系,求最大的 \(a_i \oplus a_j\),其中 \(a_i\) 是一个 \(0 \sim n - 1\) 的排列。

首先贪心的肯定要选择最大的那个,然后选择一个数(选了最大的,自然这个就是最小的了)凑出一个 \(2^k - 1\)

那么根据 \(x | x = x\),利用 \(O(n)\) 次形如 \((i, i, j, j)\) 的询问即可找出最大。

找到了 \(i\) 最大,接下来需要 \(a_i \oplus a_j = 2^k - 1\),只需要找到 \(a_i | a_j\) 最大的那些 \(j\) 中最小的那个即可。考虑满足 \(a_i | a_j\) 最大的一定是 \(a_i\) 补集的超集,而需要恰好凑出全部,那么自然是最小的那个,分别 \(O(n)\) 次即可。

B. Pinball

给定一个 <> 组成的字符串,当一个球至于其上某一个位置,其会按照一下规则运动:

  • 如果所在字符为 <,那么向左一位,否则向右。消耗 1s 时间。
  • 当球移动之后,原本所在位置字符取反,即 < 变成 >,反之同理。
  • 如果移出串内,则停止运动,既可以是左边,也可以是右边。

多组数据,给定长度为 \(n\) 的串,分别求出把球放在 \(1 \sim n\) 这些位置需要多少秒才能走出这个串。可以证明一定可以在有限步内走出。

先考虑模拟,比较容易发现,实际上球在一段反复走,向两边拓,于是可以变成双指针 \(O(n^2)\) 求。

观察双指针的本质,设出发点在 >,分讨出发点左侧(包括)> 的个数 \(S_0\) 和右边 < 的个数 \(S_1\)

\(S_0 > S_1\),那么最终会从字符串右边出去,推推式子即可;当 \(S_0 \le S_1\) 则反之,也是推推式子即可。

C. Pokémon Arena

\(n\) 神奇宝贝。一开始,竞技场上只有第 \(1\) 只神奇宝贝。

每只神奇宝贝都有 \(m\) 种属性。而第 \(i\) 只神奇宝贝的 \(j\) 属性是 \(a_{i,j}\) 。第 \(i\) 只神奇宝贝的雇佣费用是 \(c_i\)

为了最终让 \(n\) 只神奇宝贝站在竞技场,可以按照任意顺序执行以下两种操作:

  • 花费 \(k\)\(k > 0\))的代价,将 \(a_{i,j}\) 永久增加 \(k\)
  • 花费 \(c_i\) 代价雇佣第 \(i\) 只神奇宝贝与当前场上的神奇宝贝 \(k\) 决斗,并选择任意属性 \(j\)。如果 \(a_{i,j} \ge a_{k, j}\) ,则 \(i\) 击败 \(k\)\(i\) 上场,否则保持不变。

求出让第 \(n\) 只神奇宝贝站在竞技场上所需要支付的最低费用。

傻逼翻译。

最直观的想法是,一个神奇宝贝一定不要上场两次,否则直接跳过中间部分。

另一个十分重要的观察:不会连续选择相同的 \(j\)。否则不如直接跳过中间次决斗,省下雇佣费。

相当于只有去决斗前才会调整 \(a_{i, j}\),并且之后都不会在用到这个值。

于是如果让 \(i\) 用属性 \(j\)\(k\) 决斗,那么一定需要的花费是 \(c_i + \max(0, a_{k, j} - a_{i, j})\)

利用这个东西建图,可以做到 \(O(n^2 m)\)。考虑可以优化建图。

\(c_i\) 提出来,拆点处理,接下来考虑 \(\max(0, a_{k, j} - a_{i, j})\) 的边,发现实际上只需要在同层间前后缀一下即可。

于是建出图来跑 DJK 即可。

D. Bitwise Paradox

我原本以为只是支配对相关的题目,因为只有 \(O(n)\) 个对,但是带修就炸了。考虑 \(b_i | b_{i + 1} | \ldots | b_{j}\) 有一个很好的性质,在固定 \(i\) 的情况下,只有 \(O(\log V)\) 种取值。

所以放在线段树上,维护前缀,后缀,与值与最大值,合并即可。

直接合并是 \(O(\log^2 V)\) 的,但是利用支配对考虑,双指针合并变成 \(O(\log V)\)

总复杂度 \(O((n + q) \log n \log V)\)

E. Yet Yet Another Permutation Problem

首先有一个很 naive\(O(n^2)\) DP:

\[f_{i, j} = \begin{cases} [i \ge j](i - j + 1) f_{i - 1, j} + \sum_{k < j} f_{i - 1, k} & j \ne P_i \\ 0 & j = P_i \end{cases} \]

前面直接做,后面前缀和即可,最后答案是 \(f_{n, n}\)

没什么优化的前途,考虑 \(P\) 的前缀 \(\max\) 数组 \(Q\)

考虑构造出来的排列和 \(Q\) 存在某一位相同,设为 \(i\),那么需要满足 \(Q_i\)\(i\) 或者之前出现,并且 \(i\) 前都没有比 \(Q_i\) 大的。

逆着不好考虑。顺着不会考虑,还是没太懂题解的 DP 是怎么来的。

TODO。

posted @ 2023-09-10 21:36  jeefy  阅读(275)  评论(0编辑  收藏  举报