do_while_true

一言(ヒトコト)

若干道 ATCoder 题

整理点思维题,简单题/麻烦分类讨论题就不放了。

写了的题会放代码。

ARC 126 D

状压dp + 费用提前计算。

从前往后枚举 \(i\),设 \(f_S\) 为考虑集合 \(S\) 已经连在一起且排好序的代价,并且包括提前计算的费用,这里提前计算的费用是使得有一个数想加进来的时候之间按照插排的规则插入进来,走到这个段之前的代价已经在 \(f\) 里面算进去了。

这个提前计算的费用为多少?对于一个位置 \(i\) 如果不是最终的递增段,而是一个路人,那么递增段要经过它并且凑齐的最小代价是递增段在它左边多少和在它右边多少取个 \(\min\),也就是 \(\min(pop\_count(S),k-pop\_count(S))\)

形象地:

\(o...o...o..\Delta..o...o...o..o\)

假如 \(\Delta\) 是当前枚举到的 \(i\),而 \(o\) 是最终要拼成连续段的位置,那么要不然左边所有的 \(o\) 越过 \(\Delta\),要不然右边所有的 \(o\) 越过 \(\Delta\),那么 \(\Delta\) 处需要提前计算的费用就是两边 \(o\) 的个数取 \(\min\)

Code

ARC 127 C

首先先假装 \(0\) 存在,这个是不要紧的,令 \(X\gets X-1\)

然后数可以分成三类,\(0\)\(10\) 开头的,\(11\) 开头的,如果 \(X=0\),那么答案就是 \(0\);否则,若 \(1\leq X<2^{N-1}\),那么就是 \(10\) 开头,然后令 \(X\gets X-1\)\(0\) 没有了),若 \(X>2^{N-1}\),说明是 \(11\) 开头,\(X\) 减去 \(2^{N-1}\) 即可。

由于每次减去 \(2^{N-1}\) 的话是砍掉最高位可以 \(\mathcal{O}(1)\),然后 \(-1\) 的话就暴力借位,对于每一位考虑最劣情况下借位次数,其数量是 \(\sum\left \lceil \frac{n}{2^i} \right \rceil =\mathcal{O}(n)\)

trick:对于一个数,每次只有 \(+1\),或者每次只有 \(-1\),暴力进位/借位次数均摊下来是 \(\mathcal{O}(次数)\) 的。

Code

AGC 052 B

考虑边权转点权,让边权满足其为相邻点权的异或和,操作变成交换两个点的点权。

随便钦定一个为根,设 \(d_i\) 为初始时 \(i\) 的点权,\(f_i\)\(i\) 期望得到为多少。如果存在 \(d,f\),满足它们是相同的集合,就有解。

注意到如果确定了一个点的点权,那么其他所有点权都能唯一的确定。

现在钦定 \(f_i\)\(i\) 到根路径上的边权和(或者说钦定 \(f_1=0\)),注意到任何一组解都能把所有点权异或 \(f_1\),得到 \(f_1=0\) 的解,所以判断是否有解就判断 \(f_1=0\) 的时候是否有解。

现在 \(f\) 确定了,看是否存在 \(d\),满足 \(d\)\(f\) 是相同的集合。

现在继续钦定 \(d_i\)\(i\) 到根路径上边权和,与 \(f\) 相同,所有可能为答案的 \(d'\) 都是 \(d\) 异或上一个 \(x\) 得到的。

那么有解的充分条件就是 \((d_1\oplus x)\oplus (d_2\oplus x)\oplus...\oplus (d_n\oplus x)=f_1\oplus f_2\oplus...\oplus f_n\),由于 \(n\) 为奇数,所以可以解出 \(x\) 是多少。

由于这仅是充分条件,那么最后还要 \(\text{check}\) 一下是否合法。

trick:由充分(或者必要)条件可以得出答案可能的一种或多种取值,然后暴力判断必要(或者充分)条件是否满足。

Code

AGC 043 B

先作一遍差分,\(3\) 就没了,只有 \(0,1,2\)。然后注意到如果序列中存在 \(1\),那么 \(2\) 遇到 \(1\) 会变成 \(1\)\(0\) 遇到 \(1\) 也是变成 \(1\),所以最终的答案非 \(0\)\(1\),变成在模 \(2\) 意义下加法,每个数对最终结果的贡献是个组合数,Lucas算。只有 \(0,2\) 的情况也同理。

ACG 044 B

每次暴力更新最短路,由于最短路总和是 \(\mathcal{O}(n^3)\) 的,一个节点入队的话最短路一定是更新了的,所以复杂度为 \(\mathcal{O}(n^3)\)

AGC 045 B

作一下前缀和,问题变成使得前缀和的极差尽可能小。先考虑暴力怎么做是不是加边加边并查集,枚举前缀和 \(s\) 的最大值,然后从前往后贪心想使得最小值尽可能大,如果当前能填 \(+1\) 就填 \(+1\),否则填 \(-1\)

观察这个贪心,考虑到枚举的 \(s\) 的最大值 \(+2\) 之后,最多有一个 \(-1\) 变成了 \(+1\),因为上界 \(+2\) 后又 \(-2\),所以从那个位置之后的填法和之前是一样的。所以最大值 \(+2\) 之后,最大的最小值最多会 \(+2\),故不会更优。

所以只枚举可能的最小的前缀和最大值及其 \(+1\) 即可。

trick:先考虑暴力怎么做,然后给暴力剪枝/优化

ARC 128 A

假设现在有 \(x\) 克金子如果在第 \(i\) 天将金子换成银子,紧接着在第 \(j\) 天把银子换成金子,那么 \(x\gets x\times\frac{A_i}{A_j}\)

  • 把限制松一松,一天可以交换多次,发现和原问题等价,交换两次相当于没有交换。
  • 把限制紧一紧,一次对换,即在第 \(i\) 天将金子换成银子,紧接着在第 \(j\) 天把银子换成金子。仅允许 \(i+1=j\) .发现和原问题等价,\(i\) 天金到银,\(j\) 天银到金,等价于 \(i\) 天金到银,\(i+1\) 天银到金,\(i+1\) 天金到银,\(i+2\) 天银到金...\(j\) 天银到金。即 \((i,j)\) 对换,等价于 \((i,i+1),(i+1,i+2),...,(j-1,j)\) 对换。

问题转化成让 \(1\) 克金子,每次可以乘上 \(\frac{A_{i}}{A_{i+1}}\),所以只有 \(A_i>A_{i+1}\) 的时候,才选择对换 \((i,i+1)\)

对应回原问题,一笔交易被对换奇数次才相当于做这一笔交易。

trick:限制松一松/紧一紧发现和原问题等价。

Code

思维不好怎么办?第一眼可以看出暴力 dp,设 \(f_{i,0/1}\) 代表在做完前 \(i\) 笔交易,手里拿的金子/银子的最大克数,转移的时候判断大小,用 \(\log\) 来比较就可以。对应了[Code+#4]组合数问题2这道题的 trick数比较大且运算只有乘除法/次方的时候用 \(\log\) 比较大小。

posted @ 2021-10-23 06:53  do_while_true  阅读(75)  评论(0编辑  收藏  举报