###题目大意:
Miranda 准备去市里最有名的珠宝展览会,展览会有可以购买珠宝,但可惜的是只能现金支付,Miranda 十分纠结究竟要带多少的现金,假如现金带多了,就会比较危险,假如带少了,看到想买的右买不到。展览中总共有
N
N
N种珠宝,每种珠宝都只有一个,对于第
i
i
i种珠宝,它的售价为
C
i
C_i
Ci万元,对 Miranda 的吸引力为
V
i
V_i
Vi 。
Miranda 总共可以从银行中取出
K
K
K万元,现在她想知道,假如她最终带了
i
i
i万元去展览会,她能买到的珠宝对她的吸引力最大可以是多少?
###思路:
每个物品的重量很小,于是按照重量分类,对于同一个重量里面的物品一起考虑。
不难发现,贪心的选择物品,对于同一个重量,选择的物品一定是按照价值从大到小排序的一个前缀。
于是对于每一种重量的决策,体积也按照剩余类分类,不同剩余类的dp分开考虑,此时dp可以看成是连续的。
因为选择的是一个前缀,并且前缀和的斜率不断减小,不难发现满足决策单调性,简单地证明一下:
i
<
j
i<j
i<j且
i
i
i的决策点为
p
p
p,即有任意
s
<
p
s<p
s<p满足
d
p
[
s
]
+
s
u
m
[
s
,
i
]
<
d
p
[
p
]
+
s
u
m
[
p
,
i
]
dp[s]+sum[s,i]<dp[p]+sum[p,i]
dp[s]+sum[s,i]<dp[p]+sum[p,i],即
s
u
m
[
s
,
i
]
−
s
u
m
[
p
,
i
]
<
d
p
[
p
]
−
d
p
[
s
]
sum[s,i]-sum[p,i]<dp[p]-dp[s]
sum[s,i]−sum[p,i]<dp[p]−dp[s],又因为有
s
u
m
[
s
,
j
]
−
s
u
m
[
p
,
j
]
<
s
u
m
[
s
,
i
]
−
s
u
m
[
p
,
i
]
sum[s,j]-sum[p,j]<sum[s,i]-sum[p,i]
sum[s,j]−sum[p,j]<sum[s,i]−sum[p,i],所以有
d
p
[
s
]
+
s
u
m
[
s
,
j
]
<
d
p
[
p
]
+
s
u
m
[
p
,
j
]
dp[s]+sum[s,j]<dp[p]+sum[p,j]
dp[s]+sum[s,j]<dp[p]+sum[p,j]。
于是直接分治优化决策单调性就好了,所谓分治大概就是不断地确定一个区间中点的决策点,这样以后对于左区间和右区间便各自拥有了上界和下界,然后不断地递归就好了。
时间复杂度
Θ
(
300
m
log
m
)
\Theta(300m\log{m})
Θ(300mlogm)
#include<bits/stdc++.h>
#define REP(i,a,b) for(int i=a,i##_end_=b;i<=i##_end_;++i)
#define DREP(i,a,b) for(int i=a,i##_end_=b;i>=i##_end_;--i)
typedef long long ll;
using namespace std;
void File(){
freopen("loj6039.in","r",stdin);
freopen("loj6039.out","w",stdout);
}
template<typename T>void read(T &_){
T __=0,mul=1; char ch=getchar();
while(!isdigit(ch)){
if(ch=='-')mul=-1;
ch=getchar();
}
while(isdigit(ch))__=(__<<1)+(__<<3)+(ch^'0'),ch=getchar();
_=__*mul;
}
const int maxn=1e6+10;
const int maxm=5e4+10;
const int maxc=300+10;
const ll inf=LLONG_MAX>>1;
int n,m,lst[maxm],tot;
ll dp[maxc][maxm];
vector<ll>cost[maxc];
vector<ll>sum[maxc];
void init(){
read(n); read(m);
ll c,v;
REP(i,1,n)read(c),read(v),cost[c].push_back(v);
REP(i,1,300)sort(cost[i].begin(),cost[i].end());
REP(i,1,300){
ll las=0ll;
sum[i].push_back(las);
DREP(j,cost[i].size()-1,0){
las=las+cost[i][j];
sum[i].push_back(las);
}
}
}
ll calc(int len,int pre,int now){
int cnt=(now-pre)/len;
if(cnt>(int)(sum[len].size()-1))return -inf;
return dp[len-1][pre]+sum[len][cnt];
}
//c_max*m*log(m)
void divide(int len,int l,int r,int L,int R){
int mid=(l+r)>>1,pos=0; ll Max=0;
REP(i,L,min(R,mid)){
ll val=calc(len,lst[i],lst[mid]);
if(val>Max)Max=val,pos=i;
}
if(l==r){dp[len][lst[l]]=Max;return;}
divide(len,l,mid,L,pos);
divide(len,mid+1,r,pos,R);
}
void work(){
REP(i,1,300){
REP(j,0,i-1){
lst[tot=1]=j;
while(lst[tot]+i<=m)lst[tot+1]=lst[tot]+i,++tot;
divide(i,1,tot,1,tot);
}
}
REP(i,1,m)printf("%lld%c",dp[300][i],i==m ? '\n' : ' ');
}
int main(){
//File();
init();
work();
return 0;
}