#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);
}