CodeForces922E DP//多重背包的二进制优化

https://cn.vjudge.net/problem/1365218/origin

题意 一条直线上有n棵树 每棵树上有ci只鸟 在一棵树底下召唤一只鸟的魔法代价是costi 每召唤一只鸟,魔法上限会增加B 从一棵树走到另一棵树,会增加魔法X 一开始的魔法和魔法上限都是W 问最多能够召唤的鸟的个数

显然这是一道DP题

用dp[i][j]来表示到j这个树下选到j只鸟可以获得的最大能量值

很容易得出dp状态转移方程dp[i][j] = max(dp[i][j],dp[i][j - 1] - cost,dp[i - 1][j - 1] - cost);

由于每棵树上的鸟数量有限制,需要多一重大小为c的循环,但是因为∑c为1e3,三重循环的时间复杂度事实上仅为O(n * sum(c))可以接受

初始状态是dp[i][0] = W; 其他的状态为-1表示无法到达

进而可以考虑到每棵树事实上是一个多重背包,在dp的过程中考虑二进制优化,以及将dp开成滚动数组来优化空间

#include <map>
#include <set>
#include <ctime>
#include <cmath>
#include <queue>
#include <stack>
#include <vector>
#include <string>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <sstream>
#include <iostream>
#include <algorithm>
#include <functional>
using namespace std;
#define For(i, x, y) for(int i=x;i<=y;i++)
#define _For(i, x, y) for(int i=x;i>=y;i--)
#define Mem(f, x) memset(f,x,sizeof(f))
#define Sca(x) scanf("%d", &x)
#define Scl(x) scanf("%lld",&x);
#define Pri(x) printf("%d\n", x)
#define Prl(x) printf("%lld\n",x);
#define CLR(u) for(int i=0;i<=N;i++)u[i].clear();
#define LL long long
#define ULL unsigned long long
#define mp make_pair
#define PII pair<int,int>
#define PIL pair<int,long long>
#define PLL pair<long long,long long>
#define pb push_back
#define fi first
#define se second
typedef vector<int> VI;
const double eps = 1e-9;
const int maxn = 1e3 + 10;
const int maxm = 1e4 + 10;
const int INF = 0x3f3f3f3f;
const int mod = 1e9 + 7;
int N,M,tmp,K;
LL W,B,X;
LL dp[2][maxm];
PIL b[maxn];
vector<PIL>P;
int C[maxn];
int main()
{
    scanf("%d%lld%lld%lld",&N,&W,&B,&X);
    int sum = 0;
    Mem(dp,-1);
    For(i,1,N) Sca(C[i]);
    For(i,1,N){
        Mem(dp[i & 1],-1);
        dp[i & 1][0] = W;
        int c = C[i]; LL cost;
        scanf("%lld",&cost);
        P.clear();
        P.pb(mp(0,0));
        sum += c;
        //cout << sum <<endl;
        tmp = 0;
        for(int j = 1; j <= c; j <<= 1){
            P.pb(mp(j,cost * j));
            c -= j;
        }
        if(c) P.pb(mp(c,cost * c));
        for(int k = 0 ; k < P.size(); k ++){
            PIL u = P[k];
            for(int j = sum;j >= u.fi ; j--){
                if(dp[i & 1][j - u.fi] >= u.se) dp[i & 1][j] = max(dp[i & 1][j],dp[i & 1][j - u.fi] - u.se);
                if(dp[i - 1 & 1][j - u.fi] == -1) continue;
                LL t = min(dp[i - 1 & 1][j - u.fi] + X,W + B * (j - u.fi));
                if(t >= u.se) dp[i & 1][j] = max(dp[i & 1][j],t - u.se);
            }
        }
    }
    int ans;
    _For(i,sum,0){
        if(dp[N & 1][i] != -1){
            ans = i;
            break;
        }
    }
    Pri(ans);
    return 0;
}

原文地址:https://www.cnblogs.com/Hugh-Locke/p/9581694.html

时间: 2024-10-10 09:44:44

CodeForces922E DP//多重背包的二进制优化的相关文章

多重背包(二进制优化)

链接:https://www.acwing.com/problem/content/5/ 有 N种物品和一个容量是 V 的背包. 第 i 种物品最多有 si 件,每件体积是 vi,价值是 wi. 求解将哪些物品装入背包,可使物品体积总和不超过背包容量,且价值总和最大. 输出最大价值. 输入格式 第一行两个整数,N,V,用空格隔开,分别表示物品种数和背包容积. 接下来有 N 行,每行三个整数 vi,wi,si,用空格隔开,分别表示第 i 种物品的体积.价值和数量. 输出格式 输出一个整数,表示最大

HDU 1059(多重背包加二进制优化)

http://acm.hdu.edu.cn/showproblem.php?pid=1059 Dividing Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 29901    Accepted Submission(s): 8501 Problem Description Marsha and Bill own a collection

POJ 1276 Cash Machine(多重背包的二进制优化)

题目网址:http://poj.org/problem?id=1276 思路: 很明显是多重背包,把总金额看作是背包的容量. 刚开始是想把单个金额当做一个物品,用三层循环来 转换成01背包来做.T了-- 后面学习了 用二进制来处理数据. 简单地介绍一下二进制优化:?(? ? ??)  假设数量是8,则可以把它看成是1,2,4,1的组合,即这4个数的组合包括了1-8的所有取值情况.这是为什么呢?将它们转换成二进制再观察一下: 1:1 2:10 4:100 1:1 二进制都只有0,1.所以1,2,4

poj1014+hdu1059--A - Dividing(多重背包,二进制优化)

A - Dividing Time Limit:1000MS     Memory Limit:32768KB     64bit IO Format:%I64d & %I64u Submit Status Description Marsha and Bill own a collection of marbles. They want to split the collection among themselves so that both receive an equal share of

HDU 2844 Coins 多重背包(二进制优化)

点击打开链接 Coins Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 8167    Accepted Submission(s): 3327 Problem Description Whuacmers use coins.They have coins of value A1,A2,A3...An Silverland dolla

硬币问题 (dp,多重背包的二分优化)

题目描述 给你n种硬币,知道每种的面值Ai和每种的数量Ci.问能凑出多少种不大于m的面值. 输入 有多组数据,每一组第一行有两个整数 n(1≤n≤100)和m(m≤100000),第二行有2n个整数,即面值A1,A2,A3,…,An和数量C1,C2,C3,…,Cn (1≤Ai≤100000,1≤Ci≤1000).所有数据结束以2个0表示. 输出 每组数据输出一行答案. 样例输入 3 10 1 2 4 2 1 1 2 5 1 4 2 1 0 0 样例输出 8 4 背包问题的复杂度是n*m,这题如果

hdoj 1059 Dividing 【多重背包】||【优化母函数】

题意:每一种弹珠(marble)的都有各自的价值,第一种为1, 第二种为2,..,给出你每种弹珠的数量,求能不能将价值总和均分. 策略:rt: 这道题比赛的时候没有想到用母函数,就用了多重背包来解,之后递交的时候时间居然超600ms,我再一看递交排行都是0ms(⊙﹏⊙b汗).看到讨论区有人说母函数也可以,于是就写了个普通的,可惜TL了.果然还是需要优化啊...于是游来游去果然0ms(O(∩_∩)O哈哈哈~). 说一下0秒的思路,因为只是问能不能均分,所以我们没有必要找种类数,找到了就定义为1好了

POJ 1742 Coins 多重背包单调队列优化

http://poj.org/problem?id=1742 题意: 很多硬币,有价值和数量,给出一个上限,问上限内有多少种钱数可以由这些硬币组成. 分析: 好像是楼教主男人八题之一.然后学多重背包单调队列优化时看了别人的程序..所以后来写了就1A了=.= 前一篇小小总结了一下多重背包单调队列优化(http://www.cnblogs.com/james47/p/3894772.html),这里就不写了. 1 #include<cstdio> 2 #include<cstring>

poj1014 dp 多重背包

1 //Accepted 624 KB 16 ms 2 //dp 背包 多重背包 3 #include <cstdio> 4 #include <cstring> 5 #include <iostream> 6 using namespace std; 7 const int imax_n = 120005; 8 int f[imax_n]; 9 int amount[7]; 10 int v; 11 int n=6; 12 int max(int a,int b) 1