题解 AtCoder Beginner Contest 268 A~H

ABC268 solution

Author: caijianhong

A. Five Integers

题目描述

输入五个数,要求输出有多少个本质不同的数字被输入。

solution

print(len(set(input().split())))

B. Prefix?

题目描述

输入两个字符串 \(S,T\) 并判断 \(S\) 是否是 \(T\) 的一个前缀。

solution

string s, t;
cin >> s >> t;
cout << (t.find(s) == 0 ? "Yes" : "No") << endl;

C. Chinese Restaurant

题目描述

RobinChen 给你一个 \(n\) 阶排列 \(p\),它的值域和定义域都是 \([0,n)\)。现在你可以对 \(p\) 做若干次循环位移,做完以后,最大化下式:

\[\sum_{j=0}^{n-1}[p_j=j\lor p_{(j-1)\bmod n}=j\lor p_{(j+1)\bmod n}=j]. \]

solution

考虑处理出每个循环位移的答案,发现一个 \(i\) 只会向三个地方作贡献。\(O(n)\)

D. Unique Username

题目描述

\(n\) 个字符串 \(S_1, S_2, \cdots, S_n\)\(m\) 个字符串 \(T_1, T_2, \cdots, T_m\)。你需要构造一个字符串 \(X\) 满足如下所有条件:

  • \(3\leq |X|\leq 16\)
  • 不存在 \(1\leq i\leq m\) 使得 \(T_i=X\)
  • 存在 \(n\) 阶排列 \(p\)\(n-1\) 阶正整数序列 \(x\) 使得 \(X=S_{p_1}+\texttt{'_'}\times x_1+S_{p_2}+\texttt{'_'}\times x_2+\cdots S_{p_n}\),其中:
    • \(\texttt{'_'}\) 是下划线字符 _
    • \((+)::String\to String\to String\) 定义为字符串的拼接。
    • \((\times)::String\to Int\to String\) 定义为 \(S\times 1=S,S\times x=S+S\times(x-1)\)

solution

直接暴力 dfs 即可。\(O(n!)\) 外加巨大的常数,取决于具体实现,这里不展开。

E. Chinese Restaurant (Three-Star Version)

题目描述

RobinChen 给你一个 \(n\) 阶排列 \(p\),它的值域和定义域都是 \([0,n)\)。现在你可以对 \(p\) 做若干次循环位移,做完以后,设 \(q_i\) 为满足 \(p_j=i\)\(j\),最小化下式:

\[\sum_{j=0}^{n-1}\min((q_j-j)\bmod n, (j-q_j)\bmod n). \]

solution

考虑处理出每个循环位移的答案,这形如区间加等差数列,做二阶差分即可。\(O(n)\)

F. Best Concatenation

题目描述

RobinChen 给你 \(n\) 个字符串 \(S_i\),这 \(S_i\) 的字符集是 \(\{0,1,2,3,4,5,6,7,8,9,X\}\),然后 RobinChen 定义字符串 \(S\) 的价值 \(f(S)\) 为:

\[f(S)=\sum_{r=0}^9r\sum_{1\leq i<j\leq |S|}[S_i=X\land S_j=r]. \]

你需要将这 \(n\) 个字符串以适当的顺序拼接以最大化最终字符串的价值 \(f\)

输入格式

solution

考虑一个字符串内部的贡献是可以轻易计算的。然后一个观察是可以将一个数字 \(x\) 展开成 \(x\) 个数字 \(1\),明显不影响答案。故我们可以将问题变为有 \(n\)\((a_i, b_i)\),合理排序使得 \(\sum_{1\leq i<j\leq n}a_ib_j\) 最大。考虑最终排列中的 \(i\)\(i+1\),现在他们之间的贡献是 \(a_ib_{i+1}\),交换后的贡献是 \(a_{i+1}b_i\),换句话说如果相邻两个数满足 \(a_{i+1}b_i>a_ib_{i+1}\implies \frac{a_{i+1}}{b_{i+1}}>\frac{a_i}{b_i}\) 就要交换,这明显有良好的定义,于是按照 \(\frac{a_i}{b_i}\) 排序即可。\(O(n\log n)\)

G. Random Student ID

题目描述

RobinChen 的 http://cplusoj.com/d/junior/ 新来了 \(n\) 个学生,每个学生都有自己的英文 ID,RobinChen 记第 \(i\) 个学生的英文 ID 为 \(S_i\)

RobinChen 现在要为他们分配 cplusoj 的用户 ID。为了出题考察你,RobinChen 随机了字符串 abcdefghijklmnopqrstuvwxyz 的一种排列,然后定义两个字母的字典序比较, 如果 \(a\)\(b\) 在 RobinChen 随机的排列中先出现,则 \(a\) 的字典序更小。然后对于两个字符串的比较,则是逐位比较,按照刚才说的比较方法比较。一个学生的用户 ID 定义为比他英文 ID 字典序小的学生个数加一。

因为 RobinChen 的排列是随机的,他想让你求出每个学生的用户 ID 的期望。

输入格式

solution

考虑到一个事情是对于两个不同的字符 \(x,y\)\(x<y\) 的概率恰好是 \(\frac 1 2\),因为 \(x>y\) 的概率和 \(x<y\) 的概率相等,同时没有 \(x=y\) 的情况。于是我们对所有学生的英文 ID 建 Trie 树,考虑在一个节点两个儿子互相的贡献。首先自己的所有祖先的字典序会比自己小,其次自己的祖先的其他儿子会有 \(\frac 1 2\) 的概率计入我自己的答案。于是直接 dfs 一遍计算即可。\(O(n)\)

H. Taboo

题目描述

RobinChen 给你一个字符串 \(S\),你需要在 \(S\) 中选择 \(k\) 个位置将他们改成 #。然后有 \(n\) 个字符串 \(T_1, T_2, \cdots, T_n\)。你需要使修改后的 \(S\) 不含有任何一个 \(T_i\) 作为 \(S\) 的子串。最小化 \(k\)

solution

如果我们能处理出一个点 \(i\) 向前最短多少能和 \(T\) 匹配上,那么这个问题就变成了“给定 \(n\) 个区间,要求每个区间内至少种一棵树,求至少种多少棵树”。这是经典贪心问题,做法是按照一个端点排序(以右端点为例),从左向右,记录上一棵树在哪里,如果这个区间扫描到的时候已经满足要求则继续,否则在它的右端种上一棵树。那么怎么“处理出一个点 \(i\) 向前最短多少能和 \(T\) 匹配上”呢?使用 AC 自动机或者 SAM 或者 SA 即可。

codes

https://atcoder.jp/contests/abc268/submissions/me?f.Task=&f.LanguageName=&f.Status=AC&f.User=

posted @ 2023-09-25 20:46  caijianhong  阅读(73)  评论(0编辑  收藏  举报