#决策单调性dp,分治#LOJ 6039「雅礼集训 2017 Day5」珠宝

题目传送门


分析

观察到这个0/1背包中单个物品的体积不超过300,考虑分体积考虑。

\(dp[i]\) 表示容量大小为 \(i\) 的背包能获得的最大价值,

\(dp[i]=\max\{dp[i-j]+s[j]\}\) 是满足四边形不等式的,好像和凸性有关。

所以直接用决策单调性实现,枚举余数,就可以做到 \(O(m \max\{a_i\}\log m)\)


代码

#include <cstdio>
#include <cctype>
#include <functional>
#include <algorithm>
using namespace std;
const int N=50011;
struct node{int y,next;}e[N*20];
typedef long long lll;
int T,tot,n,m,mx,as[N]; 
lll dp[N],f[N],s[N*20],g[N];
int iut(){
	int ans=0; char c=getchar();
	while (!isdigit(c)) c=getchar();
	while (isdigit(c)) ans=ans*10+c-48,c=getchar();
	return ans;
}
void print(lll ans){
	if (ans>9) print(ans/10);
	putchar(ans%10+48);
}
void Max(lll &x,lll y){x=x>y?x:y;}
int max(int a,int b){return a>b?a:b;}
void dfs(int l,int r,int L,int R){
	if (l>r) return;
	int mid=(l+r)>>1,MID=L; lll ans=0;
	for (int j=max(mid-n,L);j<=mid&&j<=R;++j)
	if (g[j]+s[mid-j]>ans)
	    ans=g[j]+s[mid-j],MID=j;
	Max(f[mid],ans);
	dfs(l,mid-1,L,MID);
	dfs(mid+1,r,MID,R);
}
int main(){
	T=iut(),m=iut();
	for (int i=1;i<=T;++i){
		int x=iut(),y=iut(); mx=max(mx,x);
		e[i]=(node){y,as[x]},as[x]=i;
	}
	for (int i=1;i<=mx;++i)
	if (as[i]){
		n=0;
		for (int j=as[i];j;j=e[j].next) s[++n]=e[j].y;
		sort(s+1,s+1+n,greater<int>());
		for (int j=1;j<=n;++j) s[j]+=s[j-1];
		for (int j=0;j<i;++j){
			tot=0; for (int k=j;k<=m;k+=i) g[++tot]=dp[k],f[tot]=0;
			dfs(1,tot,1,tot);
			tot=0; for (int k=j;k<=m;k+=i) Max(dp[k],f[++tot]);
		}
	}
	for (int i=1;i<=m;++i) print(dp[i]),putchar(32);
    return 0;
}
posted @ 2022-03-23 11:05  lemondinosaur  阅读(28)  评论(0编辑  收藏  举报