一共也就7种课,第7种可以贪心地选择一定睡觉以换取答案的最小值。
那么我们就只剩下六种课需要讨论,状态压缩一下【当前的课之前睡过哪些课】即可。
本题要在二分的check内写DP,用二分出来的疲劳极限作为限制条件。
#include<cstdio> #include<cstring> #include<algorithm> #include<climits> using namespace std; template<class T> inline void read(T &_a){ bool f=0;int _ch=getchar();_a=0; while(_ch<'0' || _ch>'9'){if(_ch=='-')f=1;_ch=getchar();} while(_ch>='0' && _ch<='9'){_a=(_a<<1)+(_a<<3)+_ch-'0';_ch=getchar();} if(f)_a=-_a; } const int maxn=5001; long long n,c[maxn],js[maxn],zj[maxn],l,mid,r,init,dp[maxn][(1<<6)+5]; inline bool check() { memset(dp,0x7f,sizeof(dp)); dp[0][0]=init; for (register int i=1;i<=n;++i) { if(c[i]==7) { for (register int v=0;v<64;++v) if (dp[i-1][v]<=mid) dp[i][v]=dp[i-1][v]-js[i]; continue; } int symbol=(1<<(c[i]-1)); for (register int v=0;v<64;++v) { if(v&symbol) { if(dp[i-1][v^symbol]<=mid) dp[i][v]=dp[i-1][v^symbol]-js[i]; } else { if(dp[i-1][v]<=mid) dp[i][v]=min(dp[i][v],dp[i-1][v]+zj[i]); if(dp[i-1][v^symbol]<=mid) dp[i][v]=min(dp[i][v],dp[i-1][v^symbol]+zj[i]); } } } for (register int v=0;v<64;++v) if(dp[n][v]<=mid) return true; return false; } int main() { freopen("survive.in","r",stdin); freopen("survive.out","w",stdout); read(n); for (register int i=1;i<=n;++i) read(c[i]); for (register int i=1;i<=n;++i) read(js[i]); for (register int i=1;i<=n;++i) read(zj[i]),r+=zj[i]; read(init); l=init; r+=l; long long ans; while(l<=r) { mid=(l+r)>>1; if(check()) ans=mid,r=mid-1; else l=mid+1; } printf("%lld",ans); fclose(stdin); fclose(stdout); return 0; }