题解 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\) 做若干次循环位移,做完以后,最大化下式:
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)\)。
- \(\texttt{'_'}\) 是下划线字符
solution
直接暴力 dfs 即可。\(O(n!)\) 外加巨大的常数,取决于具体实现,这里不展开。
E. Chinese Restaurant (Three-Star Version)
题目描述
RobinChen 给你一个 \(n\) 阶排列 \(p\),它的值域和定义域都是 \([0,n)\)。现在你可以对 \(p\) 做若干次循环位移,做完以后,设 \(q_i\) 为满足 \(p_j=i\) 的 \(j\),最小化下式:
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)\) 为:
你需要将这 \(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=
本文来自博客园,作者:caijianhong,转载请注明原文链接:https://www.cnblogs.com/caijianhong/p/solution-abc268.html