AtCoder Grand Contest 044 简要题解

  因为比赛的时候在路上,所以又成功错过下分和被神仙 jerome_wei 吊起来打(按在地上摩擦)的好机会。

Problem A Pay to Win

  把这个过程倒过来。不难发现到下一次除之前,要么是加到 n/dd 要么是 n/dd,或者直接减到 0.

  直接用 map 记忆化的复杂度为 O(Tlog3NloglogN)。具体的来说,每个状态只可能是 n2a3b5c 或者 n2a3b5c,对于 nuv 的情况有 nuv=nuvnuvnuv=nuv 

Code

Problem B Joker

  容易发现初始最短路之和为 O(n3)。一个人离开后暴力更新会产生改变的位置,时间复杂度不会超过初始最短路之和。

Code

Problem C Strange Dance

  建一个 Trie 树,维护位置 i 上的是谁。

  对于 S 操作就是一个全局交换 2,3 子树。

  对于 R 操作做一次循环位移,然后暴力递归有进位的子树。

Code

Problem D Guess the Password

  考虑询问 62 次长度为 128 的全 a 串,全 b 串.....然后可以知道每种字符有多少个。

  注意到如果有一个长度为 l 的串是原串的子序列,那么如果在这个串中插入一个字符 c 使得询问的结果减少 1,这意味着插入后仍然是原串的子序列。

  考虑如果我们已经知道两个字符集不相交的串 s,t 分别是原串的子序列,我们怎么把它们合并。考虑在 s 的每个位置依次插入 t 的下一个未确定字符,然后判断它是否是原串的子序列。

  然后做一个简单归并就好了。

Code

Problem E Random Pawn

  首先假设第一个和最后一个都是 A 中最大的,如果不是这样的话可以通过旋转,然后再在后面增加一个来实现。

  因为到 A 最大的地方一定会停止,因此现在问题变成了链上。

  设 Ei 表示从 i 出发的最大期望收益,显然有 Ei=max{Ei1+Ei+12Bi,Ai}

  考虑有 Bi 非常地难处理,考虑把它搞掉。

  设 Fi=EiCi,那么有 Fi=max{Ei1Ci1+Ei+1Ci+12+Ci1+Ci+12CiBi,AiCi}

  因此 Ci 满足 Ci1+Ci+12CiBi=0。钦定 C0=C1=0,然后可以简单构造出来。

  注意到 Ci+1Ci2Bi=CiCi1 因此 Ci 大概是 2Bi 做二次前缀和,因此范围大概是 1012 左右。

  考虑最终的序列中是硬点若干位置 p,使得 Fp=Ap。接下来假定 Ai 都已经减去了 Ci

  考虑知道一段最左端为 l,最右端为 r 时怎么计算中间的贡献。不难发现中间的 F 满足 FiFi1=Fi+1Fi,因此有 Fi=(il)Ar+(ri)Alrl

  然后求一个和有 l<i<rFi=12(Al+Ar)(rl1)

  如果答案被计算两次,每一段各计算一次首尾的贡献,最终再计算一次开头和结尾的贡献。

  那么此时一段的贡献为 (Al+Ar)(rl),不难发现这个是某个梯形面积的两倍。

  不难发现取 {(i,Ai)} 的上凸壳的点的时候,这个面积能达到最大值。(因为显然这个时候 Fi 达到了最大值)

Code

Problem F Name-Preserving Clubs

  假设有 k 个集合,那么考虑建一个 k×n 的矩阵,每一位填 0 或者 1,表示这个集合中是否包含这个元素。

  首先考虑任意两个集合都不同的情况。

  如果称一个上述矩阵是好的,那么当且仅当任意打乱它的列(不能和原来相同),不存在一种方式使得打乱行和最初的矩阵相同。不难发现,这和题目中的一个 name-preserving configuration 一一对应。

  不难证明一个好的矩阵任意两列都不同,因为如果存在两列相同,我们交换这两列, 它和原来一模一样,这和定义矛盾。

  假设一个矩阵 A 是好的,可以注意到下面两个性质:

  • A 的转置 AT 是好的。
  • 考虑 2k 种不同的列,由其中所有不存在于 A 的列构成的矩阵 AC 也是好的。

  前者如果不成立,那么对应的行列操作可以应用到 A 上使得操作后和它自己相同。因为没有任意一行或者一列是相同的,所以行列都至少操作 1 次,因此这是满足定义的。

  注意到行列操作是独立的,因此先打乱行,再打乱列是等价的。

  对于后者,考虑如果不成立,那么打乱行后,使得和原来的列集合相同,可以推出,做这些打乱行操作,可以使得 A 不是好的。

推论 设 c(k,n) 表示本质不同的 k×n 的好的矩阵的数量,那么有 c(k,n)=c(n,k),c(k,n)=c(k,2kn) 

  证明由上述讨论易得。

  设 g(n) 表示最小的 k 使得 c(k,n)>0,那么有:

性质1 2g(n)ng(g(n))

  证明 不断应用推论可得 c(g(n),n)=c(g(n),2g(n)n)=c(2g(n)n,g(n)),然后由定义可得。

  设函数 G(n) 满足 G(1)=0G(n) 是最小的 k 满足 2knG(k)

引理1 对于 n>1,那么有 0G(i)G(i1)1

   证明 首先不难用归纳法证明 G(i)<i。然后 G(i)G(i1) 比较显然,这里略去证明。

  考虑用归纳法,当 n=2,3 的时候显然。

  考虑 n=i(i>3) 的情形。因为 2G(i1)(i1)G(G(i1))2G(i1)2,所以有 2G(i1)+1i2G(i1)+1(i1)G(G(i1))+1G(G(i1)+1)

引理2 对于 kG(n),那么都有 2knG(k)

   证明 考虑用归纳法,当 k=G(n) 显然成立。

   当 k>G(n) 的时候因为有 2k11,所以有 2kn2k1+1nG(k1)+1G(k)。 

引理3 c(k,n)>0 当且仅当 G(n)k2nG(n)

  证明 必要性显然,考虑充分性。

  考虑使用归纳法,当 n=1 的时候显然成立。下面当 n>1 的时候

  如果 G(n)k<n,那么可以用推论使得变为 k>n 的情形。现在我们来证明它满足条件,因为 kG(n),所以有 2knG(k),所以有 n2nG(k)。因为 k2nG(n),所以 2nkG(n),因此 nG(k),因此有 G(k)n2nG(k)

  如果 2n1<k,那么可以用推论使得变为 k<2n1 的情形。我们还是来证明它满足条件,因为 2nk<k,所以只用证明 G(n)2nk。因为 2nG(n)k,移项可得它成立。

  现在考虑 nk2n1

  考虑构造一个集合 {{1},{1,2},{2,3},{3,4},,{n1,n}}。然后对于剩下 kn 个填任意大小大于等于 3 的集合。

  可以手动验证当 n=2,n=3 可行,当 n4 的时候,满足大小大于等于 3 的集合至少占了一半,因此一定可行。

引理4 6kn2k1 时, c(k,n)>1000

  证明的思路大概是考虑先构造一个大小为 k2 的集合,包含 {1,2},{2,3},,{k2,k1},然后将其中一个或者其中 k3 个取补集。剩下的 nk+2 个集合随便塞大小不为 2 或者 k2 的集合。

  然后考虑两个集合可能相同的情况。由于 yyf 非常菜,目前还不会,所以咕咕咕咕。结论是 n=4 的时候答案加上 1,n=7 的时候答案加上 2.

  对于剩下 k5,n2k1 的情况写一个爆搜就行了。如果您的爆搜比较慢,请打表。

Code

posted @   阿波罗2003  阅读(574)  评论(0编辑  收藏  举报
编辑推荐:
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示