不死的LYM NOIP模拟 二分+状压DP

一共也就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;
}

 

posted @ 2017-10-27 21:46  JayWang  阅读(247)  评论(0编辑  收藏  举报