【BZOJ1226】學校食堂(動態規劃,狀態壓縮)
阿新 • • 發佈:2018-07-14
食堂 有關 轉移 mem sizeof fin 狀壓 set lin ,並且\(i\)之前的所有人都拿到了飯的最小值。
註意一下\(k\)的值域範圍\([-8,7]\)。
考慮轉移
首先檢查一下當前這個位置是否已經被解決。
如果是,直接轉移到\(f[i+1][j>>1][k-1]\),\(k-1\)的原因是向後推了一位。
否則,枚舉當前解決誰,計算一下貢獻就好了。
【BZOJ1226】學校食堂(動態規劃,狀態壓縮)
題面
BZOJ
洛谷
題解
發現\(b\)很小,意味著當前這個人最壞情況下也只有後面的一小部分人在他前面拿到飯。
所以整個結果的大致順序是不會變化的。
對於一個人,他要占用的時間之和前面那個拿飯的人有關。
而他前面那個拿飯的人在隊列中只有兩種情況,一種在他前面,一種在他後面。
顯然在他前面對於當前這個人是沒有任何影響的,有問題的只有在他後面的人先拿飯。
所以可以狀壓後面哪些人在當前這個人之前拿到了飯。
所以設狀態\(f[i][j][k]\)表示當前第\(i\)個人,\(i\)和後面\(b\)個人拿飯的情況是\(j\),上一個拿飯的人是\(i+k\)
註意一下\(k\)的值域範圍\([-8,7]\)。
考慮轉移
首先檢查一下當前這個位置是否已經被解決。
如果是,直接轉移到\(f[i+1][j>>1][k-1]\),\(k-1\)的原因是向後推了一位。
否則,枚舉當前解決誰,計算一下貢獻就好了。
#include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #include<cmath> #include<algorithm> using namespace std; #define ll long long #define RG register #define MAX 1010 #define cmin(a,b) (a=((a>b)?(b):(a))) inline int read() { RG int x=0,t=1;RG char ch=getchar(); while((ch<'0'||ch>'9')&&ch!='-')ch=getchar(); if(ch=='-')t=-1,ch=getchar(); while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar(); return x*t; } int f[MAX][1<<8][17],n,a[MAX],b[MAX],ans; int calc(int i,int j){if(!i)return 0;return a[i]^a[j];} int main() { int T=read(); while(T--) { n=read();ans=1e9; for(int i=1;i<=n;++i)a[i]=read(),b[i]=read(); memset(f,63,sizeof(f));f[1][0][-1+8]=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]>=1e9)continue; if(j&1)cmin(f[i+1][j>>1][k+7],f[i][j][k+8]); else { int lst=1e9; for(int l=0;l<=7;++l) { if(i+l>lst)break;if(j&(1<<l))continue; cmin(lst,b[i+l]+i+l); cmin(f[i][j|(1<<l)][l+8],f[i][j][k+8]+calc(k+i,l+i)); } } } for(int i=0;i<=8;++i)cmin(ans,f[n][1][i]); printf("%d\n",ans); } return 0; }
【BZOJ1226】學校食堂(動態規劃,狀態壓縮)