题意:你今天需要上
状压 DP。
设
那么如果第
如果第
-
如果我们选择睡,那么必须满足上次这节主科没睡,即
。 ; -
如果选择不睡,那么上节课睡不睡都没问题。
。 由于疲劳值超过了限度就会死,所以在转移时我们只有当疲劳值小于忍耐限度时才能转移。
但我们并不知道疲劳限度,怎么办?
二分答案!!
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<ctime>
#define INF 1e9
using namespace std;
const int maxn=15010;
const double Pi=acos(-1.0);
template<class T>void read(T &x)
{
x=0;int f=0;char ch=getchar();
while(ch<'0'||ch>'9') {f|=(ch=='-');ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
x=f?-x:x;
return;
}
int n,c[maxn],f[maxn][71];
int s,down[maxn],up[maxn];
int check(int limit)
{
memset(f,0x3f,sizeof(f));
f[0][0]=s;
for(int i=1;i<=n;i++)
{
if(c[i]==7)
{
for(int j=0;j<=63;j++)
if(f[i-1][j]<=limit)
f[i][j]=min(f[i][j],f[i-1][j]-down[i]);
}
else
{
int t=1<<(c[i]-1);
for(int j=0;j<=63;j++)
{
if((j>>(c[i]-1))&1)
{
if(f[i-1][j^t]<=limit)
f[i][j]=min(f[i][j],f[i-1][j^t]-down[i]);
}
else
{
if(f[i-1][j]<=limit)
f[i][j]=min(f[i][j],f[i-1][j]+up[i]);
if(f[i-1][j^t]<=limit)
f[i][j]=min(f[i][j],f[i-1][j^t]+up[i]);
}
}
}
}
for(int i=0;i<=63;i++)
if(f[n][i]<=limit)
return true;
return false;
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d",&c[i]);
for(int i=1;i<=n;i++)
scanf("%d",&down[i]);
for(int i=1;i<=n;i++)
scanf("%d",&up[i]);
scanf("%d",&s);
int l=s,r=INF,mid;
while(l<r)
{
mid=(l+r)>>1;
if(check(mid))
r=mid;
else
l=mid+1;
}
printf("%d",l);
return 0;
}