[NOIP2018 普及组] 摆渡车
记 f i f_i fi 为 i i i 时刻发车,处理完等车时间 ≤ i \le i ≤i 的学生的最小花费。
线性 dp。考虑枚举分界点 j j j,将时间在 j + 1 j+1 j+1 到 i i i 的学生打包在 i i i 时刻送走,花费为 ∑ i − t x \sum i - t_x ∑i−tx,其中 t x t_x tx 在 j + 1 j+1 j+1 到 i i i 之间。时间复杂度 O ( T 2 ) O(T^2) O(T2)。代码
注意到 j + 1 j+1 j+1 到 i i i 超过 2 m 2m 2m 可以再次分段。 时间复杂度 O ( m T ) O(mT) O(mT)。代码
一开始我还想了一种错误的解法:记 f i f_i fi 表示处理完前 i i i 个人的最小花费,记 g i g_i gi 表示处理完前 i i i 个人的到站时间,我们贪心的让 g g g 越小越好。代码。错误之处在于 不具有最优子结构。具体来说,考虑到 g g g,最优的 f f f 并不一定能推出最优解。
竞速溜冰
用废了 i i i 个人,领队体力为 h e a d head head,跑了 t o t tot tot 圈。每次决策换不换领队。代码
注意: 应当先判断不合法在判断边界。
火柴数字(二)
此题另一种做法可以参考 我同学的博客,两者大体思路差不多 。
对于前 50% 的数据,设计 f ( i , j , k ) f(i,j,k) f(i,j,k) 表示位数为 i i i、用 j j j 根火柴、余数为 k k k 的最优答案。答案在 k = 0 k=0 k=0 中找最大 即可。时间复杂度 O ( n 2 m ) O(n^2m) O(n2m)。 代码
分析超时原因,考虑将其中一维转成收益。设计 f ( i , j ) f(i,j) f(i,j) 表示 位数为 i i i、余数为 j j j 的最小花费火柴数量。容易求出最终答案的位数 l e n len len。
统计出 l e n len len 后,考虑从高位往低位从大往小填数。由于需满足位数,我们应当保证填完第 i i i 位后, i i i 的低位仍然存在合法方案。
具体地,假设第 i i i 位填了 d d d、 i i i 的高位填了 c u r s u m cursum cursum 根火柴、 i i i 的高位余数为 c u r m o d curmod curmod。可推出 i i i 的低位余数 k k k:
c u r m o d × 1 0 i + d × 1 0 i − 1 + k ≡ 0 ( m o d m ) curmod \times 10^i + d \times 10^{i-1} + k \equiv 0 \pmod m curmod×10i+d×10i−1+k≡0(modm)
k ≡ − c u r m o d × 1 0 i − d × 1 0 i − 1 ( m o d m ) k \equiv - curmod \times 10^i - d \times 10^{i-1}\pmod m k≡−curmod×10i−d×10i−1(modm)
则 d d d 应满足 c u r s u m + a d + f ( i − 1 , k ) ≤ n cursum + a_d + f(i-1,k) \le n cursum+ad+f(i−1,k)≤n。
预处理 10 10 10 的幂次即可,时间复杂度 O ( n m ) O(nm) O(nm)。
总结:状态转收益从而降维。
Cow Exhibition G
状态转收益。代码。
[CEOI2005] Mobile Service
第一问比较容易设计 f ( i , j , k ) f(i,j,k) f(i,j,k) 表示三个快递员分别在 j , k , p i j,k,p_i j,k,pi 的最小花费。
第二问要求在较小的空间限制输出方案。我们考虑根据最终的答案状态推出所有时刻的状态。考虑每一步决策推到上一步决策的过程,朴素方式是记录两个位置,事实上只需要记录转移到
p
i
p_i
pi 的位置即可,该过程因递推过程的状态转移而异。实现可以使用 unsigned char
。
在推出每次决策的位置后。又因初始位置已知,我们容易得到任意时刻快递员的变化情况。
乘积凑整
状态转收益。 f ( i , j ) f(i,j) f(i,j) 表示选 i i i 个数 j j j 个 5 5 5 最多得到几个 2 2 2。代码
一开始的错误做法:记录三个状态, 2 , 5 , 10 2,5,10 2,5,10 分别最多。这样是有后效性的,即第一关键字相等情况下选 2 , 5 2,5 2,5 取决于后续状态。
平分数字(二)
简单题。 f ( i , j ) f(i,j) f(i,j) 表示前 i i i 个,A 比 B 多 j j j 的最大取值。代码
完美匹配
前 i i i 个黑棋,白棋匹配状态为 m a s k mask mask。 m a s k mask mask 决定了 i i i。复杂度 O ( n 2 n ) O(n2^n) O(n2n)。代码
棋盘覆盖
想象成国际象棋棋盘,发现一块骨牌覆盖一个黑点和一个白点。然后就是二分图的最大匹配。
Round Numbers S
数位 dp。需要注意前导零带来的影响。
[AGC020C] Median Sum
如果考虑 0 0 0,子集和是对称出现的。子集和 可重集 的中位数,相当于在子集和的 不重集 里找中间数。
子集和(四)
完全背包。 f ( i ) f(i) f(i) 表示和为 i i i 的方案数。
考虑到一维的时候顺序任意,不妨令 a i a_i ai 为最后一个数。 f ( t ) − f ( t − a i ) f(t) - f(t-a_i) f(t)−f(t−ai) 即可。
消失之物
上一题的 01 背包版本。考虑将最后一轮倒序撤销贡献即可。
[BalticOI 2010 Day2] Candies
我们发现,当某一个数被替换为无穷大时,选其方案不会与不选其方案有交集,替换后方案数等于不选这一个数方案数的两倍。因此 P P P 应当满足不选其时方案数最大, Q Q Q 应当在满足无交集的基础上最小。
对于 P P P 的求解就是上一题。
对于 Q Q Q,考虑什么时候有交集:
存在一组 S 1 , S 2 ( P ∉ S 1 , S 2 ) S_1,S_2(P \notin S_1,S_2) S1,S2(P∈/S1,S2) 满足下式:
Q + ∑ j ∈ S 1 b j = ∑ j ∈ S 2 b j Q + \sum_{j\in {S_1}} b_j= \sum_{j \in S_2} b_j Q+j∈S1∑bj=j∈S2∑bj
Q = ∑ j ∈ S 1 b j + ∑ j ∈ S 2 ( − b j ) Q = \sum_{j \in S_1} b_j + \sum_{j\in {S_2}} (-b_j) Q=j∈S1∑bj+j∈S2∑(−bj)
仍然是背包问题,bitset
求解。
方案数很大,由于只需判断是否存在,考虑取模。模数小有概率出错。
Sum of Distances P
先考虑 K = 2 K=2 K=2 时怎么做。
对于点 ( a , b ) (a,b) (a,b), ( 1 , 1 ) (1,1) (1,1) 能到 ( a , b ) (a,b) (a,b) 当且仅当 G 1 G_1 G1 中 1 1 1 到 a a a 距离、 G 2 G_2 G2 中 1 1 1 到 b b b 距离奇偶性相同。
记 o d d i , e v e n i odd_i,even_i oddi,eveni 分别表示 G 1 / G 2 G_1/G_2 G1/G2 中 1 1 1 到 i i i 的奇 / 偶距离,可通过 bfs 求解。则 G G G 中 ( 1 , 1 ) (1,1) (1,1) 到 ( a , b ) (a,b) (a,b) 距离:
d i s a , b = min ( m a x ( o d d a , o d d b ) , max ( e v e n a , e v e n b ) ) dis_{a,b}=\min ( max (odd_{a},odd_{b}),\max(even_{a},even_{b})) disa,b=min(max(odda,oddb),max(evena,evenb))
由此考虑分别记录
G
1
,
G
2
G_1,G_2
G1,G2 中通过 奇 / 偶 步到达每个点的最小步数。答案为:
∑
d
i
s
i
,
j
=
∑
max
(
o
d
d
i
,
o
d
d
j
)
+
∑
max
(
e
v
e
n
i
,
e
v
e
n
j
)
−
∑
max
(
o
d
d
i
,
e
v
e
n
i
,
o
d
d
j
,
e
v
e
n
j
)
\sum dis_{i,j}=\sum \max(odd_{i}, odd_{j})+\sum \max(even_{i},even_{j}) - \sum \max(odd_{i}, even_i, odd_j, even_j)
∑disi,j=∑max(oddi,oddj)+∑max(eveni,evenj)−∑max(oddi,eveni,oddj,evenj)
抽象问题,考虑 ∑ i , j max ( a i , b j ) \sum_{i,j} \max(a_i,b_j) ∑i,jmax(ai,bj) 怎么算。这里直接拓展到 K K K 维。考虑桶排,每次取最小值,每个数的贡献就是这个数的值乘以已经扔出去的数中其他组中小于等于它的个数。预处理逆元可做到 O ( n ) O(n) O(n)。
需注意:
- K K K 组元素均出现后才计算贡献。
- 为避免相同元素之间贡献的重复计算,设值为 x x x,编号为 i i i,其贡献为编号在 1 1 1 到 i − 1 i-1 i−1 中 ≤ x \le x ≤x 的数以及编号在 i i i 到 n n n 中 < x <x <x 的数。因此考虑相同值按图的编号排序,可以直接统计小于等于的个数。
Inspection
让我们先回顾一下 清理雪道 这道题。我们通过一些转换将问题变成了最大流问题,并得到了最小路径数量以及转换后的流 f ′ f' f′。我们将 f ′ f' f′ 转化为 f f f 后便得到了每条边的覆盖次数。
现试构造一种最优方案。采用类似拓扑排序的方式解决。
Naptime G
一个环形 dp 的新套路,就是跑两遍。第一遍强制序列。第二遍强制成环,即钦定第 n n n 天睡觉后正常做。
管道取珠
∑ a i 2 \sum a_i^2 ∑ai2 的意义就是两个人玩这个游戏然后这两个人结果一样的方案数。
直接 Alice Bob 拿了前多少个珠子,然后一些 trival 的优化即可。
Wish I Knew How to Sort
01 序列,主要考察位置。最终序列形如 000...111
。而这个分界线又是容易确定的。故统计在分界线前的
1
1
1 个数
x
x
x。
f
(
x
)
=
x
2
(
n
2
)
f
(
x
−
1
)
+
(
1
−
x
2
(
n
2
)
)
f
(
x
)
+
1
f(x) = \frac {x^2}{\binom{n}{2}} f(x-1) + (1-\frac {x^2}{\binom{n}{2}}) f(x) + 1
f(x)=(2n)x2f(x−1)+(1−(2n)x2)f(x)+1。化简得
f
(
x
)
=
f
(
x
−
1
)
+
(
n
2
)
x
2
f(x) = f(x-1) + \binom {n}{2} x^2
f(x)=f(x−1)+(2n)x2。
Video Game Troubles G
一发过了。把 n n n 个主机看成 n n n 行,每行做 0-1 背包。用的是背包常用滚动技巧, f ( i , 0 / 1 ) f(i,0/1) f(i,0/1) 表示用了 i i i 容量,当前行是/否已购买主机的最大收益。