zoukankan      html  css  js  c++  java
  • 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
    ", x)
    #define Prl(x) printf("%lld
    ",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;
    }
  • 相关阅读:
    最长上升子序列问题总结
    Problem C
    Problem C
    Problem P
    Problem P
    Problem H
    Problem H
    Problem D
    Problem D
    Linux系统调用--getrlimit()与setrlimit()函数详解
  • 原文地址:https://www.cnblogs.com/Hugh-Locke/p/9581694.html
Copyright © 2011-2022 走看看