AtCoder Beginner Contest 236 题解

\(A,B,C\) 题过水,不作赘述,我的 \(Atcoder\) 号是 \(Complex\) ,需要代码可以去找找。

\(D\)\(Dance\)

\(2n\) 个人按每组两人分成 \(n\) 组,第 \(i\) 人和第 \(j\) 人同一组会产生 \(A_{i,j}\) 的贡献,求 \(n\) 组贡献值的异或和最大值。

\(1\le n\le8\)

评分 \(1190\) ,其实真实难度完全达不到这个分的难度。

注意到数据很小,提示我们搜索也许可做,直接枚举排列然后按顺序两个人分一组,复杂度是 \(O((2n)!)\) ,肯定过不去,又注意到有很多重复计算的情况,选择时给人打标记,如果当前人已经有标记,直接去下一层,否则枚举比当前的人编号大的且未被分组的人进行搜索,每次人数减少 \(2\) ,最大复杂度是 \(15*13*...*1\) ,可过。

\(E\)\(Average\) \(and\) \(Median\)

给定 \(n\) 个数的序列 \(A\) ,相邻的两个数里面至少要有一个被选出来,求选出来的数字构成的新序列的平均值和中位数最大值,设新序列长度是 \(L\) ,其中中位数的定义为该序列中从小到大数第 \(\lceil L/2\rceil\) 大的数字。

\(2\le n\le 100000\) , \(1 \le A_i\le10^9\)

评分 \(1900\) ,是一道质量很高的题目。

其实见到平均数和中位数的常用套路就是二分答案,这题第一步就是二分这两个数字。

注意到一个序列的平均数如果大于 \(K\) ,那么序列中每个数减去 \(K\) 之后,序列和一定 \(>0\) ,利用这个性质,我们直接在二分答案判定时,对 \(A\) 中的数字都减去当前判定的答案 \(mid\) ,此时在满足题目要求的选数规则的前提下,如果能选出一个和 \(>0\) 的子序列,那么这个平均数就是合法的 ,可以尝试更大的数字,那么怎么找这个子序列呢?其实只需要能选出的最大子序列和 \(>0\) 就行了,用一个线性 \(DP\) 解决。

\(f[i][1/0]\) 表示在前 \(i\) 个数里面选择,且 第 \(i\) 个数保证是选/不选的最大子序列和。

那么根据题意,相邻的数必须至少选一个,方程很好写:

\(f[i][1]=max(f[i-1][0],f[i-1][1])+a[i]-mid\) ,当前已经选,上一个选不选都可以

\(f[i][0]=f[i-1][1]\) ,当前没选,上一个必须选

最后判断 \(max(f[n][1],f[n][0])\) 是否是 \(\ge0\) 即可(注意取等!)。

那么中位数呢?方法是类似的,中位数一定是原序列中的某一个数,于是重新用一个数组复制一次 \(A\) 序列,然后从小到大排序(不能直接对 \(A\) 排序,这样会打乱相邻数位置),然后二分下标即可,对 \(\ge\) 当前判断答案的数字的权值设为 \(1\) ,其余设为 \(-1\) ,求最大子序列和是否 \(>0\) 即可(注意此处不取等)。

时间复杂度 \(O(nlogn)\)

posted @ 2022-01-25 19:58  Constant1227  阅读(178)  评论(0)    收藏  举报