P2157 SDOI2009 學校食堂
阿新 • • 發佈:2020-07-19
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))\)
\(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