bzoj1226/luogu2157 学校食堂 (状压dp)

我们先约定:(左) 窗口_人人人人人 (右)

可以发现,我们只需要知道最靠左的还没打饭的人 以及它身后7个人的状态 以及上一个打饭的人是谁

因为他左面的就都打过了 右面7个人以后肯定还没打

可以设f[i][j][k]表示这是第i个人,身后7个人的状态是j,上一个打饭的是k

但其实上一个打饭的离他最远也就是8,所以可以只记i和k的差值,为了避免出负数再加个10之类的

考虑怎么转移,有两种情况

1.i身后的某个人打饭:找到j中是0的一位x,同时保证x左面的没打饭的人+这个人的容忍度<=x,也就是保证这个转移合法

2.i自己打饭:找到i右面第一个是0的位置,转移到这个位置

转移的时候更新一下k就好了

 1 #include<bits/stdc++.h>
 2 #define CLR(a,x) memset(a,x,sizeof(a))
 3 using namespace std;
 4 typedef long long ll;
 5 typedef pair<int,int> pa;
 6 const int maxn=1050,maxs=260,maxb=20;
 7 
 8 inline ll rd(){
 9     ll x=0;char c=getchar();int neg=1;
10     while(c<'0'||c>'9'){if(c=='-') neg=-1;c=getchar();}
11     while(c>='0'&&c<='9') x=x*10+c-'0',c=getchar();
12     return x*neg;
13 }
14 
15 int N,v[maxn],f[maxn][maxs][maxb],b[maxn],bin[maxb];
16 
17 int gettime(int i,int j,int k){
18     return (i+k-10)?(v[i+j]|v[i+k-10])-(v[i+j]&v[i+k-10]):0;
19 }
20 
21 int main(){
22     //freopen("","r",stdin);
23     int i,j,k,l;
24     bin[1]=1;for(i=2;i<=8;i++) bin[i]=bin[i-1]<<1;
25     for(int T=rd();T;T--){
26         N=rd();
27         for(i=1;i<=N;i++)
28             v[i]=rd(),b[i]=rd();
29         for(i=N+1;i<=N+10;i++)
30             b[i]=23333;
31         CLR(f,127);
32         f[1][0][9]=0;int ans=1e9+1;
33         for(i=1;i<=N;i++){
34             for(j=0;j<bin[b[i]+1];j++){
35                 for(k=0;k<=10+b[i];k++){
36                     if(f[i][j][k]>=1e9) continue;
37                     int mi=23333333;
38                     for(l=1;l<=b[i]&&l<=mi;l++){
39                         if(!(j&bin[l])) f[i][j|bin[l]][l+10]=min(f[i][j|bin[l]][l+10],f[i][j][k]+gettime(i,l,k));
40                         if(!(j&bin[l])) mi=min(mi,l+b[i+l]);
41                     }
42                     for(l=1;l<=b[i];l++)
43                         if(!(j&bin[l])) break;
44                     f[i+l][j>>l][10-l]=min(f[i+l][j>>l][10-l],f[i][j][k]+gettime(i,0,k));
45                     if(i+l>N) ans=min(ans,f[i+l][j>>l][10-l]);
46                 }
47             }
48         }
49         printf("%d\n",ans);
50     }
51     return 0;
52 }

 

posted @ 2018-11-13 08:13  Ressed  阅读(112)  评论(0编辑  收藏  举报