zoukankan      html  css  js  c++  java
  • bzoj3163 Eden的新背包问题

    多重背包,$q$ 次询问,每次问删一个物品之后花费 $x$ 能装多少物品

    $n leq 3000, x leq 1000, q leq 300000$

    sol:

    网上有很多假做法

    正解应该是考虑分治

    先二进制拆物品,然后记 $solve(l,r)$ 表示不考虑 $[l,r]$ 的操作的 dp

    每次递归的时候先把 $[mid+1,r]$ 的 dp 数组搞出来,然后递归 $[l,mid]$,然后删除 $[mid+1,r]$

    同样的,把 $[l,mid]$ 的 dp 数组搞出来,递归 $[mid+1,r]$ ,然后删除 $[l,mid]$

    递归到 $[l,l]$ 的时候会确保只有 $[l,l]$ 区间没被算

    这样每层实际上只跑了一次 dp,分治有 log 层,所以复杂度是 $O(n^2log^2n)$ (拆物品带一个 log,重量与 $n$ 同级)

    单调队列可以少一个 log

    #include<bits/stdc++.h>
    #define LL long long
    #define rep(i,s,t) for(register int i = (s),i##end = (t); i <= i##end; ++i)
    #define dwn(i,s,t) for(register int i = (s),i##end = (t); i >= i##end; --i)
    using namespace std;
    inline int read()
    {
        int x=0,f=1;char ch;
        for(ch=getchar();!isdigit(ch);ch=getchar())if(ch=='-')f=-f;
        for(;isdigit(ch);ch=getchar())x=10*x+ch-'0';
        return x*f;
    }
    const int maxn = 50010;
    vector<pair<int, int> > qs[maxn];
    int n, dfn, curdep;
    int a[maxn], b[maxn], lb[maxn], rb[maxn];
    int ans[10 * maxn], dp[1010], fzd;
    void cdq(int l, int r) {
        if(l == r) {
            rep(i, 0, qs[l].size() - 1) ans[qs[l][i].second] = dp[qs[l][i].first];
            return;
        }
        int mid = (l + r) >> 1;
        int tmp[1010];
        memcpy(tmp, dp, sizeof(tmp)); //fzd++;
        rep(i, lb[mid+1], rb[r]) dwn(j, 1000, a[i]) dp[j] = max(dp[j], dp[j - a[i]] + b[i]);
        cdq(l, mid);
        memcpy(dp, tmp, sizeof(dp)); //fzd++;
        rep(i, lb[l], rb[mid]) dwn(j, 1000, a[i]) dp[j] = max(dp[j], dp[j - a[i]] + b[i]);
        cdq(mid+1, r);
        memcpy(dp, tmp, sizeof(dp)); //fzd++;
    }
    int main()
    {
        n = read();
        rep(i, 1, n) {
            int u = read(), v = read(), w = read(), j;
            lb[i] = dfn + 1;
            for(j=1;(j<<1)<=(w+1);j<<=1)  dfn++, a[dfn] = u * j, b[dfn] = v * j;
            if(w+1-j>0) dfn++, a[dfn] = (w+1-j) * u, b[dfn] = (w+1-j) * v;
            rb[i] = dfn;
        }
        int q = read();
        rep(i, 1, q) {
            int x = read() + 1, y = read();
            qs[x].push_back(make_pair(y, i));
        }
        cdq(1, n);
        rep(i, 1, q) printf("%d
    ", ans[i]);
        //if(fzd >= 3 * n) cout << "False" << endl;
    }
    View Code
  • 相关阅读:
    验证foreach 能否操做更改原表
    asp.net post/get 公共方法
    C# json日期转换
    学数学
    2742: [HEOI2012]Akai的数学作业
    BZOJ2208
    树状数组求逆序对
    网络流复习计划
    SG函数学(hua)习(shui)记录
    SPLAY板子
  • 原文地址:https://www.cnblogs.com/Kong-Ruo/p/10562205.html
Copyright © 2011-2022 走看看