2019字节跳动ACM程序设计冬令营题解

day1

【E√,F√,G√】

  签到。

【B,H,I】

  待补。

【A√】

  题意:有 $k(\leq 1000) 个选手和 \(N(\leq 1000)\) 个评委。每个评委给出一个长度为 \(k\) 的排列,表示对每个选手的喜欢程度。选手的最终名次是这么决定的:从 \(1\) 号评委开始,每次当前评委选取最厌恶的(且名次待定的)选手,将其设为名次待定选手中的最后一名。如果 \(n<k\),评委循环决策,直到确定了所有选手的名次。现在你是 \(v\) 号评委,只有你还未给出排列。你关注 \(k\) 号选手。现在你能任意设定排列,求 \(k\) 号选手最终排名最好能是多少。
  题解:先假设没有评委 \(v\) 模拟一遍,确定出依次被确定出的选手编号(轮到第 \(v\) 号评委时用 \(o\) 表示): \(xxxxoxxxxoxxyxoxx\dots\)。设 \(y\) 表示 \(k\) 的位置。现在我们要找一些选手将它们填到 \(o\) 里,使得 \(y\) 的位置尽量靠后。首先,优先放 \(y\) 之后的所有选手,因为这样 \(y\) 的排名不发生变化。如果还有空格需要填 \(y\),此时我们会发现,无论把哪个数字提前,\(y\) 的位置必然会前进。而如果我们每次把 \(y\) 之前的那个数提上去,\(y\) 的位置必然前进 \(1\) ——即这必然是最优解。所以确定 \(v\) 号评委排列时,我们只需先把 \(x\) 后面的数字塞进去,随后把 \(x\) 前面的数字逆序塞进去。

【C√】

  题意:给出一个长度小于 \(5000\) 的字符串。将其所有子串排序并连接。有 \(M(\leq 5000)\) 个询问,每次问新串第 \(k\) 位的字符是什么。
  题解:构出后缀自动机直接遍历的复杂度是 \(O(N^2 \sum)\) 的,不太优美。
  观察 \(height\) 数组。假设我们在考虑 \(l \sim r\) 这些排名的后缀。设 \(L=min(ht[l+1] \dots h[r])\),容易发现,长度为 \(1,2,\dots,L\) 的前缀必然依次排布在新串开头,且各有 \(r-l+1\) 个。对于长度更长的子串,我们可以把\((l,r)\) 分成两半,这两半字典序严格递增。现在问题独立,先递归前一半再递归后一半。单次询问复杂度 \(O(|S|)\),总复杂度 \(O(|S|^2+M|S|)\)

【D√】

  题意:给出一个长度小于 \(3000\) 的字符串,求有多少种划分方案,使得每一段字典序都是严格递增的。
  题解:有个经典操作是,设 \(diff_{i,j}\) 表示后缀 \(i\) 和后缀 \(j\) 的第一个不同位置,这个可以递推预处理出。倒着dp,设 \(f_{i,j}\) 表示后缀 \(i\) 的划分里,第一段是 \(S_{i \sim j}\) 的方案数。转移时枚举 \(k\),把合法的 \(f_{j+1,j}\) 累加进答案。显然 \(k\) 是有单调性的,可直接根据 \(diff_{i,j}\) 计算出来,再套个前缀和优化即可。

【J√】

  题意:给出两棵 \(2N-2(N \leq 1000)\) 个点的树,保证每个点度数是 \(1\)\(3\),且叶节点编号为 \(1 \sim N\)。问有多少对四元组 \((A,B;C,D)\),满足 \(A,B,C,D\) 是叶子,且第一棵树上 \(A \sim B\)\(C \sim D\) 的有交性和第二棵树上相反。
  题解:转化成:求在两棵树上都不交的四元组个数。考虑枚举 \((A,B)\)\(LCA\) 统计个数。因为我们在无根树上考虑问题,要拓展这个 \(LCA\) 的“定义”。严格地来说,对于一组合法的 \((A,B,C,D)\),定义 \(x\)\(A \sim B\) 路径上里路径 \(C \sim D\) 最近的点。我们每次枚举第一棵树上的 \(x\) 和第二棵树上的 \(x\) 并统计答案。容易发现,每个合法四元组会被统计两次。
  每次枚举度数为 \(3\) 的点。其中两个度分别放 \(A\)\(B\),另一侧放 \((C,D)\)(只需统计点的个数 \(t\),方案数就是 \(C_t^2\))。我们可以借助有根树的 \(DFS\) 序快速维护答案。因为有两棵树,可行点数是它们的交。这是一个经典问题,对于一个点 \(x\),假设它在两棵树上的 DFS 序是 \((u_x,v_x)\),将其看做一个点,每次就是矩形询问。因为是离线的,我们可以二维前缀和预处理,就支持 \(O(1)\) 询问啦。
  还有一种直接 DP 的做法:我们枚举第一棵树 \((A,B)\) 的 LCA。将第一个分叉的所有叶子在第二棵树的对应位置标为 \(1\),第二个分叉标为 \(2\),第三个分叉标为 \(3\)。对于第二棵树里的所有从 \(1\)\(2\) 的路径,它将该树化成了若干个连通块,我们要求每个联通块 \(C_X^2\) 的和。这可以通过比较麻烦的树形 DP \(O(N)\) 求出来。总复杂度也是 \(O(N^2)\)

【K√】

  题意:有一个 \(N \times N(N \leq 300)\) 的数字矩阵。求一个子矩阵,使得 “数字和” 比上 “周长” 最大。
  题解:直接做是 \(N^3 log V\) 的:枚举上下边界后分数规划。有一个小 trick是:每次做到一组上下边界时,先去 check 一下当前答案,如果不合法直接退出二分过程。这个做法的理论复杂度是 \(O(N^3+N^2 \log V)\) 的。
  上述证明可以抽象成这么一个问题。我们有 \(N^2\) 个箱子,每个箱子可以 \(O(N \log V)\) 确定它的解,或者 \(O(N)\) 验证一组解可不可行。现在要求所有箱子解的最大值。考虑一种做法:每次随机选择一个箱子确定它的最优解 \(X\)。然后遍历所有箱子 \(O(N)\) check,如果 \(X\) 不是该箱子的解就扔掉这个箱子。对于剩下的箱子继续这么做。这样的复杂度是 \(T(M)=N \log V+MN+T(x)\),其中 \(x\)\(0 \sim M\) 里随机的。事实上,这个复杂度等于 \(T(M)=N \log V+MN+T(\frac{N}{2})\)

【C√】
  题意:给出一个字符串 \(S(|S| \leq 10^5)\)。有 \(Q(\leq 3 \times 10^5)\) 个询问,每次给出 \((l,r)\),问 \(l \sim r\) 之间有多少本质不同的子串。
  题解:如果用 \(manacher\) 求出每个位置的回文半径 \(p_i\),那么对于一个询问 \((l,r)\),答案就是 \(\sum_{i=l}^r \min(p_i,i-l+1,r-i+1)\)。比赛时我想的是,每次枚举一个位置 \(i\),去维护它对所有询问 \((l,r)\) 的贡献。\(min\) 里面有 \(3\) 个量不太好直接维护。假设我们维护好了\((l,r)\) 的答案,如果边界变动一格,我们可以用主席树在 \(O(\log N)\) 的时间内求出增量(比如 \(l\) 减一,就是询问 \(\sum_{i=l}^{(l+r)/2} [p_i<l]\)。那么我们可以分块,先用差分数组在 \(O(N \sqrt N)\) 时间内维护出 \(f_{b,r}\) ,表示第 \(l\) 个块的开头到位置 \(r\) 的答案。每次询问时移动 \(l\) 求增量,询问复杂度 \(O(Q \sqrt N\log N)\)。但这样是过不了的。发现每次移动的询问是彼此独立的,可以先离线下来(为了防止空间不够,可以每隔几百万离线求一次),用桶排+树状数组快速求出答案,几乎可以把原来的主席树的 \(O(\log N)\) 的常数给拿掉。
  发现比赛中智商--。反过来考虑,直接固定一个 \((l,r)\),求所有 \(p\) 对它的贡献。 根据 \(mid\) 划成两半,三维 \(min\) 就直接变成了二维 \(min\)……然后离线+线段树或者直接主席树就在 \((N \log N)\) 时间内轻松解决了……

猜你喜欢

转载自www.cnblogs.com/jiangshibiao/p/10426489.html
今日推荐