2018.09.08【POI2005】【BZOJ1531】Bank notes (多重背包)(二进制拆分)

版权声明:转载请声明出处,谢谢配合。 https://blog.csdn.net/zxyoi_dreamer/article/details/82532592

传送门


解析:

多重背包二进制拆分法板子题。

一种物品,多种个数对答案的影响显然可以拆分成 2 i 形式,那么复杂度直接降为 l o g

据说这道题有单调队列优化做法,以后再更。


代码:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define re register
#define gc getchar
#define pc putchar
#define cs const

inline
ll getint(){
    re ll num=0;
    re char c;
    while(!isdigit(c=gc()));
    while(isdigit(c))num=(num<<1)+(num<<3)+(c^48),c=gc();
    return num;
}

inline
void outint(ll a){
    static char ch[23];
    if(a==0)pc('0');
    while(a)ch[++ch[0]]=(a-a/10*10)^48,a/=10;
    while(ch[0])pc(ch[ch[0]--]);
}

int n;
int b[201],c[201];
int a[4002],cnt;
int d[4002];
int k;
int f[20002];

int logn[20002];

int dp[20002];

int main(){
    logn[1]=0;
    for(int re i=2;i<=20000;++i){
        logn[i]=logn[i>>1]+1;
    }
    n=getint();
    for(int re i=1;i<=n;++i)b[i]=getint();
    for(int re i=1;i<=n;++i)c[i]=getint();
    k=getint();
    for(int re kk=1;kk<=n;++kk){
        for(int re i=0;i<=(logn[c[kk]]);++i){
            a[++cnt]=(1<<i)*b[kk];
            d[cnt]=(1<<i);
        }
        a[++cnt]=(c[kk]-(1<<logn[c[kk]]))*b[kk],d[cnt]=(c[kk]-(1<<logn[c[kk]]));
        if(a[cnt]==0)--cnt;
    }
    memset(dp,0x3f,sizeof dp);
    dp[0]=0;
    for(int re i=1;i<=cnt;++i){
        for(int re j=k;j>=a[i];--j){
            dp[j]=min(dp[j],dp[j-a[i]]+d[i]);
        }
    }
    cout<<dp[k]<<endl;
    return 0;
}

猜你喜欢

转载自blog.csdn.net/zxyoi_dreamer/article/details/82532592