agc022 题解
A \(\color{Gray}\bigstar\)
要么在后面加一位,要么找到一个可以加一的位置去加。
B \(\color{green}\bigstar\)
全部 \(\gcd\) 起来要是 \(1\),那直接放 \(2,3\) 即可,然后剩下的相当于在 \(2,3\) 的倍数中找,要求和是 \(6\) 的倍数,可以发现总个数恰好是 \(20000\),然后贪心放即可。
注意 \(n=3\) 需要特判。
C \(\color{green}\bigstar\)
没啥意思,从高到底每一位确定是否放即可。
判定是一个简单背包。
D \(\color{blue}\bigstar\)
到达商场 \(i\) 的时间满足
结束时间就是 \(t+t_i\),那么结束后再出发的时间也可以求,假设是 \(g_i\)。
那么从 \(i\) 走到 \(j\) 就可以算贡献了:
\(x_i<x_j\),如果 \(x_i\) 的时间是 \(2Lk+x_i\),注意我们把在路程上行走的时间放到前后点上算,这里只算在商场内的贡献,也就是 \(\left \lceil\frac{t_i}{2L} \right \rceil\times 2L\)。
如果 \(x_i\) 的时间是 \(2Lk-x_i\),那么时间就是 \(\left \lceil\frac{t_i-2x_i}{2L} \right \rceil\times 2L+2x_i-2x_i=\left \lceil\frac{t_i-2x_i}{2L} \right \rceil\times 2L\)。
\(x_i>x_j\) 也类似,这样可以做到每个点贡献独立。
容易发现相当于要求一个哈密顿回路,那么每个点要么被穿过,要么右边进来左边出去,令它为 \(1\) 类点,要么左边进来右边出去,令它为 \(2\) 号点,并且这些贡献都是可以算的。
那么可以发现相当于是一个括号匹配问题,要求前缀 \(1\) 号点个数大于 \(2\) 号点,这样就一定能串起来。
简单做法是直接考虑 dp,记录前缀 \(1-2\) 的数量即可,复杂度 \(O(n^2)\)。
可以发现如果初始把所有点设为直接穿过的点,然后剩余的点里去选 \(1,2\) 类点,每选一个对答案的贡献为 \(\{-2L,0,2L\}\)。
把所有贡献为 \(-2L,0\) 的东西拿出来,相当于进行括号匹配,求尽量多的匹配,每个位置可以填左括号,右括号,或者两者都可以填。
直接贪心,分别维护左括号和两周的可以的括号,右括号贪心和左括号匹配,剩下再贪一下即可。
E \(\color{blue}\bigstar\)
判定一个是否合法,显然优先操作三个 \(0\),或者是 \(0\) 与一个 \(1\) 抵消。
发现这个过程直接维护前缀是对的,即记录前缀 \(1,0\) 个数。
\(0\) 个数显然很少因为 \(>3\) 可以直接操作,但 \(1\) 个数可能很多,不好搞。
但是发现前缀 \(1\) 数量其实很少,因为如果 \(>3\),那么一定合法,因为把后面全部操作完最多也就一个 \(0\)。
直接从左向右 dp 即可。
F \(\color{blue}\bigstar\)
下面的题解是搬到模拟赛中的版本,\(n\le 600\),并且输出 \(1...n\) 中每个的答案。
不简单的简单计数。
考虑最后的数一定形如 \(\sum a_ix^i\) 的形式。
可以发现对于不同的 \(a\),这个结果一定不一样,所以就是对 \(a\) 计数。
可以把每一个点看成多项式,每次相当于选一个 \(F_i,F_j\),然后合并成 \(2F_i-F_j\)。
由于两个多项式一定不会有相交的部分,所以可以考虑把答案写成一个二叉树的形式,每个点只有 \(0\) 或者 \(2\) 个儿子,然后左儿子是 \(2x\),右儿子是 \(-x\),然后根节点的值是 \(1\),这样就可以得到整个 \(a\) 序列。
对于一个 \(a\) 序列,如何判断其合法?
正着去生成很困难,考虑倒过来,每次合并两个数,最后合并成 \(1\)。
每次合并 \(2^{i+1}\) 和 \(-2^i\),然后变成一个 \(2^i\)。
这个过程直接贪心,每次肯定选最大的两层里的东西去合并。
直接大力 dp,设 \(f_{i,j,k,s}\) 表示从大到小做到 \(2^i\),\(2^i\) 有 \(j\) 个,\(-2^i\) 有 \(k\) 个,\(\ge 2^i\) 的数有 \(s\) 个的方案数。
转移很简单,枚举当前这层选了 \(x,y\) 个 \(2^i,-2^i\),然后和上一层合并,容易发现无论怎么合并结果都一样,转移是:
大力做,复杂度 \(O(n^6)\),结果:
离谱,原题 \(n\le 50\),并且只需要输出 \(n\) 的结果。
先考虑怎么做 \(1...n\) 的答案。
里面的东西只有组合数和 \(n\) 有关,又是一个多重集组合数,因此把 \(n!\) 拿到外面,里面变成 \(\frac{1}{x!}\frac{1}{y!}\) 即可。
这样复杂度 \(O(n^6)\),期望得分 \(40\)。
考虑优化这个东西,首先发现第一位显然没用,因为只需要关心 \(s\) 即可,所以可以直接去掉,这样复杂度 \(O(n^5)\),期望得分 \(50\),这是原题的 std 做法。
然后考虑里面的条件只和 \(j-k\) 有关,因此把 \(j-k\) 放在状态里,复杂度轻松 \(O(n^4)\),期望得分 \(60\) 分,把大一点的数据打表只有可以得到 \(80\) 分。
然后会发现 \(j-k\) 根据 \(>0,<0\) 分类,可以发现要么限制 \(x\),要么限制 \(y\),所以可以先转移一个放到一个 \(g\) 里去,再转移另一个即可。
\(j=k\) 的时候要特殊处理一下。
复杂度 \(O(n^3)\),std 只跑了 \(1.1s\)。