Luogu2157 [SDOI2009] 学校食堂 - dp -

题目链接:https://www.luogu.com.cn/problem/P2157

题解:
注意每个决策会跟其在前面还没有选过的人有关(bi),会和上一次选的人有关
考虑 dp[i][S][k] 表示考虑到第 i 个人,[i,i+7] 是否选了的状态是 S ,最后一个选的位置是 i+k
转移:

  • dp[i][S][k]dp[i+1][S>>1][k1],其中 S&1=1,这就是当前人已经取完了的情况,注意此时不参与下面的转移
  • dp[i][S][k]+f(k,l)dp[i][S|(1<<l)][l],其中 f(k,l) 就是做这个菜的时间,而且有 lS

细节若干:

  • k[8,7] -8 是因为极端情况下 bi=7,然后这个人等后面7个人都吃完了再吃,这样转移到的是 i+8
  • S 枚举到 (281),而不是 2bi+11,这是因为可能出现下面的第三种情况
  • 题意里的小细节:注意是当前人才会愤怒,而且比如说当前第 i 个人的时候让 i+2 先走,然后该 i+1 走的时候,此时 i+2 已经没有了,紧跟着的第一个人从 i+3 算起,这也就意味着不能预处理,只能根据状态 S 求出当前人最远能容忍到哪里
// by SkyRainWind
#include <bits/stdc++.h>
#define mpr make_pair
#define debug() cerr<<"Yoshino\n"
#define rep(i,a,b) for(int (i)=(a);(i)<=(b);(i)++)
#define pii pair<int,int>

using namespace std;

typedef long long ll;
typedef long long LL;

const int inf = 1e9, INF = 0x3f3f3f3f, maxn = 1005;

int n,a[maxn],b[maxn];
ll dp[maxn][(1 << 8)+5][17];
int st[maxn][9];

void ck(ll &a,ll b){a = min(a, b);}

void solve(){
	memset(dp,0x3f,sizeof dp);
	memset(st,0,sizeof st);
	scanf("%d",&n);
	for(int i=1;i<=n;i++)scanf("%d%d",&a[i],&b[i]),st[i][0]=1;
	
	for(int k=1;k<=7;k++){
		for(int i=1;i+k<=n;i++){
			if(k <= b[i]){
				st[i][k] = 1;
				for(int j=i+1,t=k;j<=i+k-1;j++,t--){
					st[i][k] &= st[j][t-1];
				}
			}
		}
	}
	
	for(int k=0;k<=b[1];k++)if(st[1][k]){
		dp[1][1 << k][k + 8] = 0;
	}
	
	for(int i=1;i<=n;i++)
		for(int S=0;S<=(1 << b[i]+1)-1;S++){
			for(int k=max(-8, -i+1);k<=7&&i+k<=n;k++){
				if(S & 1){
					ck(dp[i+1][S >> 1][k+7], dp[i][S][k+8]);
					continue;
				}
				if(k >=0){
					if((S&(1<<k)) && k <= b[i]);
					else continue;
				}
				// k + 8
				int fi = inf;
				for(int l=0;l<=b[i]&&i+l<=n;l++)if((S&(1<<l)) == 0){
					if(i+l>fi)break; 
					fi = min(fi, i+l+b[i+l]);
					int T = S ^ (1<<l);
					ck(dp[i][T][l + 8], dp[i][S][k + 8] + (a[i+k]|a[i+l]) - (a[i+k]&a[i+l]));
				}
			}
		}
	ll res = inf;
	for(int i=-8;i<=0;i++)ck(res, dp[n][1][i + 8]);
	cout << res << '\n';
}

signed main(){
//	freopen("Luogu2157.in","r",stdin);
	int te=1;scanf("%d",&te);
	while(te--)solve();

	return 0;
}
posted @   SkyRainWind  阅读(15)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 记一次.NET内存居高不下排查解决与启示
点击右上角即可分享
微信分享提示