CF题解合集

cf,题解,合集 · 浏览次数 : 12

小编点评

**题面分析** 该题面描述一个算法求能,要求给定一棵树,每个节点要么没有儿子,要么有两个儿子,每个叶子节点有一个权值。多次修改某个叶子节点的权值,维护递推式子。最终会得到很多个答案,取最大的即可。 **算法分析** 该算法采用一个 **Goldberg Machine** 的思想,即枚举所有可能的答案。 * **枚举所有可能的树结构** * **对于每个树结构** * 计算所有叶子节点的权值和 * 如果权值最重,则将该树结构加入答案中 * 否则,继续枚举其他树结构 **代码分析** 该代码使用了 Python 的语言,并实现了 **Goldberg Machine** 的思想。 * **`GoldbergMachine`** 类中包含了以下方法: * `__init__` 方法用于设置参数 * `__calc__` 方法用于计算答案 * `__is__` 方法用于判断是否为叶节点 * `__repr__` 方法用于生成代码 **总结** 该题面描述了一个 **Goldberg Machine** 的算法求能,要求给定一棵树,每个节点要么没有儿子,要么有两个儿子,每个叶子节点有一个权值。最终会得到很多个答案,取最大的即可。

正文

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\)

\(\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

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

\(\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)\) 做即可,只是要扫很多遍而已。

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\) 的点。

于是,就搞定了。

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\) 了,可以认为完全正确。

于是就做完了。

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.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)\) 做法新鲜出炉!

18xx

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}\),使得最终的答案大于错误的答案,所以如此是没有问题的。

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

与CF题解合集相似的内容: