#决策单调性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;
}