#dp#洛谷 4399 [JSOI2008]Blue Mary的职员分配

题目


分析

\(dp[i][day][j][k]\)表示当前雇员个数为\(i\)
距离上次发广告时间为\(day\),获得的金钱和声望分别为\(j,k\)
注意\(day\)\([0\sim 3]\)范围内,状态转移方程其实挺好写的


代码

#include <cstdio>
#include <cctype>
#include <cstring>
#define rr register
using namespace std;
int m,x,y,z,A,B,mx,dp[21][4][21][21],ans;
inline signed min(int a,int b){return a<b?a:b;}
inline void Min(int &a,int b){a=a<b?a:b;}
signed main(){
	scanf("%d%d%d%d%d%d",&m,&x,&y,&z,&A,&B),
	memset(dp,42,sizeof(dp)),mx=A>z?A:z,
	ans=dp[0][0][0][0],dp[m][0][0][0]=0;
	for (rr int i=m;i<21;++i)
	for (rr int day=0;day<4;++day)
	for (rr int j=0;j<=mx;++j)
	for (rr int k=0,now;k<=B;++k)
	if (ans>(now=dp[i][day][j][k])){
		if (j>=A&&k>=B) {ans=now; continue;}//达到要求
		for (rr int I=0;I<=i;++I){//枚举选择贡献金钱的职员
			rr int a=min(j+I*x,mx),b=min(k+(i-I)*y,B);
			if (day==1||day==2) Min(dp[i][day+1][a][b],now+1);//发布广告过一天
			else {
				Min(dp[i+day/3][0][a][b],now+1);//招募到人
				if (a>=z) Min(dp[i+day/3][1][a-z][b],now+1);//发布广告
			}
		}
	}
	return !printf("%d",ans);
}
posted @ 2020-08-18 22:16  lemondinosaur  阅读(94)  评论(0编辑  收藏  举报