[SDOI2009]学校食堂

题目传送门

这道题的思想是$DP$。

首先通过简单推理发现:$(a|b)-(a\&b)=a\hat{} b$。[$(a\ and\ b) - (a\ or\ b) = a\ xor\ b$]

发现对于第$i$个同学的饭菜的选择受到2方面影响:

是否在前面的某个没有选择的同学$>B_i$的位置;

上一次选择的同学。

观察数据信息可知$B_i \leq 7$。

也就是说如果选择了第$i$个,那么最多只能选到第$i+7$个同学。前提是第$i$位同学之前全部选完了。

所以我们用状压写。同时记录上一轮选的同学相对于第$i$位同学的位置,推算得范围一定在$-8\sim 7$之间(包含两边)。

设$f[i][S][x]$为第$i$个之前的同学全部选完,$S$为第$i$到$i+7$同学是否选择的状态,$x$同上,

当第$i$位同学已选择,就可以转移到$f[i+1][S>>1][x-1]$;

其他任意情况时,当第$i+bit$位同学可以被选择时(指不超过未选择的$B[i]$到$B[i+bit-1]$的范围),可以转移到$f[i][S | (1 << bit)][bit]$,贡献为$T[i+x]\hat{} T[i+bit]$,再取最小值即可。

边界:$f[1][0][-1] = 0$,其余为$INF$。

注意$x>0$和第一轮的异或结果为$0$,特判一下即可。

因为C++下标不能为负,注意下标偏移。

 1 #include <bits/stdc++.h>
 2 
 3 using namespace std;
 4 
 5 #define re register
 6 #define rep(i, a, b) for (re int i = a; i <= b; ++i)
 7 #define repd(i, a, b) for (re int i = a; i >= b; --i)
 8 #define maxx(a, b) a = max(a, b);
 9 #define minn(a, b) a = min(a, b);
10 #define LL long long
11 #define inf (1 << 30)
12 
13 inline int read() {
14     int w = 0, f = 1; char c = getchar();
15     while (!isdigit(c)) f = c == '-' ? -1 : f, c = getchar();
16     while (isdigit(c)) w = (w << 3) + (w << 1) + (c ^ '0'), c = getchar();
17     return w * f;
18 }
19 
20 const int maxn = 1e3 + 10;
21 
22 int C, N, T[maxn], B[maxn];
23 
24 int f[maxn][1 << 8][16];
25 
26 int main() {
27     C = read();
28     rep(kase, 1, C) {
29         N = read();
30         rep(i, 1, N) T[i] = read(), B[i] = read();
31         memset(f, 0x3f, sizeof(f));
32         f[1][0][7] = 0;
33         rep(i, 1, N) {
34             rep(S, 0, 255) {
35                 int p = 7;
36                 rep(x, 0, p) {
37                     if (!(S & (1 << x)))
38                         rep(j, 0, 15) {
39                             if (i+j-8 == 0) T[i+j-8] = T[i+x]; 
40                             else if (i+j-8 < 0) continue; // 这两句if要注意,可能是 0~80pts 的原因
41                             minn(f[i][S | (1 << x)][x + 8], f[i][S][j] + (T[i+j-8] ^ T[i+x]));
42                             minn(p, B[i+x]+x);
43                         }
44                 }
45                 rep(x, 0, 15)
46                     if (S & 1) minn(f[i+1][S >> 1][x-1], f[i][S][x]);
47             }
48         }
49         int ans = inf;
50         rep(i, 0, 8) minn(ans, f[N][1][i]);
51         printf("%d\n", ans);
52     }
53     return 0;
54 }

 

posted @ 2019-01-30 14:47  AC-Evil  阅读(181)  评论(0编辑  收藏  举报