题意
有
件物品,每件物品有一个价格
和价值
,现在对于所有的
,求出用
元最多可以得到多大价值的物品。
分析
其实就是一个背包问题。
我们可以利用
很小的性质,设
表示价格不大于
的所有物品,花了
元能得到的最大价值。
假如知道了选的物品数
,那么肯定会选择价值最大的
件物品。
如果暴力枚举
的话,复杂度是
,不难注意到这个dp有决策单调性,那么可以通过分治来做到
.
代码
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<vector>
typedef long long LL;
const int N=50005;
int n,m,a[N],tot,mx;
LL f[305][N];
std::vector<LL> w[305];
int read()
{
int x=0,f=1;char ch=getchar();
while (ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while (ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
bool cmp(int x,int y)
{
return x>y;
}
void solve(int l,int r,int L,int R,int id)
{
if (l>r) return;
int mid=(l+r)/2,pos=L;
for (int i=std::max(L,mid-(int)w[id].size());i<=std::min(mid,R);i++)
if (f[id-1][a[i]]+(i==mid?0:w[id][mid-i-1])>f[id][a[mid]])
{
f[id][a[mid]]=f[id-1][a[i]]+(i==mid?0:w[id][mid-i-1]);
pos=i;
}
solve(l,mid-1,L,pos,id);solve(mid+1,r,pos,R,id);
}
int main()
{
n=read();m=read();
for (int i=1;i<=n;i++)
{
int x=read(),y=read();
mx=std::max(mx,x);
w[x].push_back(y);
}
for (int i=1;i<=mx;i++)
{
std::sort(w[i].begin(),w[i].end(),cmp);
for (int j=1;j<w[i].size();j++) w[i][j]+=w[i][j-1];
}
for (int i=1;i<=mx;i++)
for (int j=0;j<i;j++)
{
tot=0;
for (int k=j;k<=m;k+=i) a[++tot]=k;
solve(1,tot,1,tot,i);
}
for (int i=1;i<=m;i++) printf("%lld ",f[mx][i]);
return 0;
}