Processing math: 100%

bzoj3163 Eden的新背包问题

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

n3000,x1000,q300000

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(n2log2n) (拆物品带一个 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\n", ans[i]);
    //if(fzd >= 3 * n) cout << "False" << endl;
}
View Code
复制代码

 

posted @   探险家Mr.H  阅读(214)  评论(0编辑  收藏  举报
编辑推荐:
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
阅读排行:
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
点击右上角即可分享
微信分享提示