P1833 樱花(混合背包+二进制优化板子)

    科技2025-10-29  9

    https://www.luogu.com.cn/problem/P1833


    思路:首先比较容易想到是取和不取的背包问题,其次发现里面有完全背包和多重背包。所以朴素的做法就是当前物品是多重背包时候,用多重背包的解法,当前背包是完全背包时候,用完全背包的解法。

    这样会T两个点。当然你开O2可以过,但是没必要。

    #include<iostream> #include<vector> #include<queue> #include<cstring> #include<cmath> #include<map> #include<set> #include<cstdio> #include<algorithm> #define debug(a) cout<<#a<<"="<<a<<endl; using namespace std; const int maxn=1e5+100; typedef long long LL; LL dp[maxn],t[maxn],c[maxn],p[maxn]; int main(void) { ///cin.tie(0);std::ios::sync_with_stdio(false); LL a1,a2,a3,a4; scanf("%lld:%lld",&a1,&a2); scanf("%lld:%lld",&a3,&a4); LL n;scanf("%lld",&n); LL times1=0; LL times2=0; times1=a1*3600+a2*60; times2=a3*3600+a4*60; LL T=(times2-times1)/60; for(LL i=1;i<=n;i++){ scanf("%lld%lld%lld",&t[i],&c[i],&p[i]); } memset(dp,0,sizeof(dp)); for(LL i=1;i<=n;i++) { if(p[i]==0){ for(LL j=t[i];j<=T;j++) { dp[j]=max(dp[j],dp[j-t[i]]+c[i]); } } else { for(LL k=1;k<=p[i];k++) { for(LL j=T;j>=t[i];j--) { dp[j]=max(dp[j],dp[j-t[i]]+c[i]); } } } } printf("%lld\n",dp[T]); return 0; }

     


    考虑优化:在做多重背包的部分,是朴素的把其物品拆成一个一个的,考虑每个取还是不取,成为了一个01背包问题,转化成枚举取几个。

    那么这里是可以用类似倍增的思想二进制优化的。

    记录当前物品的总个数(假设有n个)和总价值,按照二进制将其log(n)堆,同时每一堆的价值是该堆的数量×该物品的单价。

    比如8件单价为4的物品A,分成(1,4),(2,8)(4,16)(5,20)最多了。当然这里最后的那部分不够20就直接把最后一部分凑成一堆。

    这样选几个的问题转化到了选几堆的问题,比如选1和3堆,就相当于选了5个,总和为20的物品,对应原来01中朴素的一个个选的时候枚举到5个的时候。

    代码上注意:空间给够。因为要考虑每个物品多出来的数量。

    #include<iostream> #include<vector> #include<queue> #include<cstring> #include<cmath> #include<map> #include<set> #include<cstdio> #include<algorithm> #define debug(a) cout<<#a<<"="<<a<<endl; using namespace std; const int maxn=999999; typedef long long LL; LL dp[maxn],t[10010],c[10010],p[10010],col[maxn],val[maxn]; LL cnt=0,n; void pre() { for(LL i=1;i<=n;i++){ LL tot=1; while(p[i]>0) { col[++cnt]=tot*t[i]; val[cnt]=tot*c[i]; p[i]-=tot;tot*=2; if(p[i]<tot&&p[i])///2020.10.21.update:&&p[i](虽然这里没事,但是判定性问题的时候会多出一个cnt { col[++cnt]=p[i]*t[i]; val[cnt]=c[i]*p[i]; break; } } } } int main(void) { LL s1,s2,s3,s4; scanf("%lld:%lld",&s1,&s2); scanf("%lld:%lld",&s3,&s4); LL times1=s1*3600+s2*60; LL times2=s3*3600+s4*60; LL T=(times2-times1)/60; scanf("%lld",&n); for(LL i=1;i<=n;i++){ scanf("%lld%lld%lld",&t[i],&c[i],&p[i]); if(p[i]==0) p[i]=999999; } pre(); for(LL i=1;i<=cnt;i++) { for(LL j=T;j>=col[i];j--) { dp[j]=max(dp[j],dp[j-col[i]]+val[i]); } } cout<<dp[T]<<endl; }

     

    Processed: 0.014, SQL: 8