P2157 SDOI2009 学校食堂
P2157 SDOI2009 学校食堂
\((a~or~b)-(a~and~b)=(a~xor~b)\)
看数据,\(B_i\)为7,考虑状压\(B_i\),设\(f[i][j][k]\)为\(1-(i-1)号已经打完;i个及以后7个人打饭的状态l;当前最后一个打饭的人的编号为i+k,不这样存k会太大\)
当\(j\&1 ==1,表示第i个人打完饭了,i以后的7个人,还没打饭的就再不会插在i前面,这\)
\(个时候就可以转移到f[i+1][j>>1][k-1]\)
\(f[i+1][j>>1][k-1]=min(f[i+1][j>>1][k-1],f[i][j][k])\)
不需要累积时间\((因为在j\&1为真的情况下,f[i][j][k]和f[i+1][j>>1][k−1]的意义是一样的)\)
\(j\& 1\ne1时,后面可以插队,f[i][j|(1<<l][l]=min(f[i][j|(1<<l)][l],f[i][j][k]+time(i+k,i+l))\)
\(f[1][0][7]意思是最后一个为1 + (-1),也就是0\)
\(i+k号人和i+l号人\) 注意判不要让前面的angry就好
答案为$f[n+1][0][k] $
因为\(k\in[-8,7],还要加一个\Delta=8把他们变正\)
#include<cstdio>
#include<cstring>
#include<iostream>
#define maxn 1005
#define INF 0x3f3f3f3f
using namespace std;
int n,t[maxn],b[maxn],f[maxn][1<<8][20],ans=INF;
//1~(i-1)号已经打完;i个及以后7个人打饭的状态l;最后一个打饭的人的编号为i+k
int main(){
int T;
scanf("%d",&T);
while(T--){
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d%d",&t[i],&b[i]);
memset(f,0x3f,sizeof(f));
f[1][0][7] = 0;
for(int i=1;i<=n;i++)
for(int j=0;j<(1<<8);j++)
for(int k=-8;k<=7;k++)
if(f[i][j][k+8] != INF){
if(j & 1) f[i+1][j>>1][k+7]=min(f[i+1][j>>1][k+7],f[i][j][k+8]);
else{
int tem = INF;
for(int l=0;l<=7;l++){
if (!((j>>l)&1)){//特判
if (i+l>tem)break;
tem=min(tem,i+l+b[i+l]);
f[i][j|(1<<l)][l+8] = min(f[i][j|(1<<l)][l+8],f[i][j][k+8]+(i+k ? (t[i+k]^t[i+l]) : 0));
}
}
}
}
for (int i=0;i<9;i++) ans=min(ans,f[n+1][0][i]);
printf("%d\n",ans);
ans =INF;
}
}
调自闭了,就是最后没把ans赋值成INF qwq