zoukankan      html  css  js  c++  java
  • [Contest on 2020.4.2] 影帝杯狂欢赛

    \(\sf Eden\) 的新背包问题

    解法

    因为每次只会删掉一个,而且不会保留。先分别预处理出从前往后,从后往前的多重背包。询问时假设去掉玩偶 \(x\),枚举前 \(x-1\) 个玩偶的花费 \(w\),就可以这样转移

    \[\text{Ans}=\max_{w=0}^m\{pre_{x-1,w}+suf_{x+1,m-w}\} \]

    复杂度是 \(\mathcal O(nmc+qm)\) 的。

    不过事实上可以用 \(\rm cdq\) 分治来优化这个过程。假设分治到区间 \([l,r]\) 时得到的 \(\mathtt{dp}\) 值是删去 \([l,r]\) 得到的最大值。那么显然 \([l,\text{mid}]\)\((\text{mid},r]\) 有贡献;\((\text{mid},r]\)\([l,\text{mid}]\) 有贡献。所以我们可以先计算出 \([l,\text{mid}]\)\(\mathtt{dp}\) 值再进入 \((\text{mid},r]\),另一半同理。

    具体 \(\mathtt{dp}\) 时还可以进行单调队列优化。假设加入物品 \((c_i,val_i)\)。枚举容量 \(j\) 取模 \(c_i\) 的余数 \(r\),对每种余数分别 \(\mathtt{dp}\)

    \[dp_{i,j}=\max\{dp_{i-1,k\cdot c_i+r}-k\cdot val_i\}+\frac{j}{c_i}\cdot val_i \]

    实现的时候要记得是将 \(i-1\) 状态的 \(\mathtt{dp}\) 值放入队列。

    复杂度是 \(\mathcal O(nV\cdot \log n)\)

    代码

    #include <cstdio>
    #define print(x,y) write(x),putchar(y)
    
    template <class T>
    inline T read(const T sample) {
    	T x=0; char s; bool f=0;
    	while((s=getchar())>'9' or s<'0')
    		f|=(s=='-');
    	while(s>='0' and s<='9')
    		x=(x<<1)+(x<<3)+(s^48),
    		s=getchar();
    	return f?-x:x;
    }
    
    template <class T>
    inline void write(const T x) {
    	if(x<0) {
    		putchar('-'),write(-x);
    		return;
    	}
    	if(x>9) write(x/10);
    	putchar(x%10^48);
    }
    
    #include <queue>
    #include <vector>
    #include <cstring>
    #include <iostream>
    using namespace std;
    
    const int maxn=1005,maxq=3e5+5;
    
    int n,a[maxn],b[maxn],c[maxn];
    int ans[maxq],ban[maxq],V[maxq];
    int dp[12][maxn];
    vector <int> g[maxn];
    deque < pair<int,int> > q;
    
    void getDp(int d,int x) {
    	for(int r=0;r<a[x];++r) {
    		while(!q.empty())
    			q.pop_back();
    		q.push_back(make_pair(0,dp[d][r]));
    		for(int i=1;i*a[x]+r<=1000;++i) {
    			while(!q.empty() and
    				q.back().second<=dp[d][i*a[x]+r]-i*b[x])
    					q.pop_back();
    			q.push_back(make_pair(i,dp[d][i*a[x]+r]-i*b[x]));
    			while(!q.empty() and q.front().first<i-c[x])
    				q.pop_front();
    			dp[d][i*a[x]+r]=max(dp[d][i*a[x]+r],q.front().second+i*b[x]);
    		}
    	}
    }
    
    void dicon(int d,int l,int r) {
    	if(l==r) {
    		for(int i=0;i<g[l].size();++i)
    			ans[g[l][i]]=dp[d-1][V[g[l][i]]];
    		return;
    	}
    	int mid=l+r>>1;
    	memcpy(dp[d],dp[d-1],sizeof dp[d]);
    	for(int i=mid+1;i<=r;++i)
    		getDp(d,i);
    	dicon(d+1,l,mid);
    	memcpy(dp[d],dp[d-1],sizeof dp[d]);
    	for(int i=l;i<=mid;++i)
    		getDp(d,i);
    	dicon(d+1,mid+1,r);
    }
    
    int main() {
    	n=read(9); int q;
    	for(int i=1;i<=n;++i)	
    		a[i]=read(9),b[i]=read(9),c[i]=read(9);
    	q=read(9);
    	for(int i=1;i<=q;++i) {
    		ban[i]=read(9)+1,V[i]=read(9);
    		g[ban[i]].push_back(i);
    	}
    	dicon(1,1,n);
    	for(int i=1;i<=q;++i)
    		print(ans[i],'\n'); 
        return 0;
    }
    
  • 相关阅读:
    Codeforces1101G (Zero XOR Subset)-less 【线性基】【贪心】
    Codeforces1101F Trucks and Cities 【滑动窗口】【区间DP】
    HDU4651 Partition 【多项式求逆】
    BZOJ2554 color 【概率DP】【期望DP】
    codeforces1101D GCD Counting 【树形DP】
    codechef EBAIT Election Bait【欧几里得算法】
    BZOJ2434 [NOI2011] 阿狸的打字机 【树链剖分】【线段树】【fail树】【AC自动机】
    codeforces1093G Multidimensional Queries 【线段树】
    BZOJ3277 串 【后缀数组】【二分答案】【主席树】
    AHOI2013 差异 【后缀数组】
  • 原文地址:https://www.cnblogs.com/AWhiteWall/p/12360206.html
Copyright © 2011-2022 走看看