[SDOI2009] 学校食堂 题解
题面:
有 $n$ 个人在排队打饭
依此给出 $n$ 个人的权值,第 $i$ 人权值为 $A_i$
输入顺序就是排队顺序(排队顺序不能变)
每个人还有一个容忍度,第 $i$ 个人容忍度为 $B_i$
表示他容忍紧跟在后面的 $B_i$ 个人比他先打饭
给一个人打饭的花费与上一个打饭的人的权值 $A_{i1}$ 有关,设当前打饭人权值为 $A_{i2}$
则花费为 $(A_{i1}\ or\ A_{i2})-(A_{i1}\ and\ A_{i2})$
让你给定一个打饭顺序,在满足所有人的容忍度情况下总花费最小
乍一看感觉要死,完全没有思路?怎么想都是指数级做法?
那就对了!因为我们缺了一个数据范围!
数据范围 $n\le 1000,A_i\le 1000$
还是没有思路?
最后一个数据范围 $B_i\le 7$
?!!!!!
好的这下能猜出算法了吧
没错就是状压dp!
显然需要状压的是第 $i$ 个人以后(包括 $i$ )的打饭情况
我们思考还有什么会影响结果?
已经打过饭的人、最后一个打饭的人
设 $f_{i,j,k}$ 表示第 $i$ 个人以前打过饭(不包括 $i$ ), $i$ 到 $i+B_i$ 的打饭情况为 $j$ (二进制位压缩),最后一个打饭的人是 $k$
列完了状态,我们来分析一下复杂度吧
$i$ 有 $n$ 个, $j$ 有 $2^(max\ B+1)=2^8=256$ 个, $k$ 有 $n$ 个
转移需要枚举一个新的打饭人,转移复杂度 $8$
总复杂度 $n^2\times 256\times 8\approx 1000^2\times 1000=1e9$
时间爆炸,空间也好不到哪里去
但真的只能这样了吗?状态真的没有冗余吗?
我们发现状态中第 $i$ 人之前的都打过饭了,而这些人也有后面 $B$ 人之后不能在他之前打饭这个限定
所以第 $i-9$ 个人不可能是最后一个打饭的,否则第 $i-1$ 个人会在第 $i-9$ 个人之前打饭,不符合规定
所以 $i-8\le k\le i+7$
虽然有了这个范围,但还是不能直接优化,我们设 $k'=k-i+8$ ,则 $0\le k'\le 15$ ,我们有了一个正常的状态
设 $f_{i,j,k'}$ 表示第 $i$ 个人以前打过饭(不包括 $i$ ), $i$ 到 $i+B_i$ 的打饭情况为 $j$ (二进制位压缩),最后一个打饭的人是 $k'+i-8$
到这里复杂度就降下来了,把一个 $n$ 降成了一个 $15$ 的常数
然而这题的实现是十分困难的,调试了不知道多久最后和题解找不同才发现错误wsl
要注意的有几点:
初值所有都是正无穷,除了几个能第一个打饭的设为0
在枚举下一个打饭人 $m$ 时要满足对于所有 $x$ 没有打饭且 $x < m$ 时 $m \le x + B[x] $
当前的 $m$ 不能已经打过饭
当 $f[i][j][k]$ 满足 $j\&1\neq 0$ 时,要将其转移到 $f[i+1][j>>1][k-1]$
最后答案取 $\min_{k=0}^8 f[n+1][0][k]$
讲完了,祝大家身体健康。