[loj6039]珠宝
决策单调性优化dp。
不难推出DP式子 ,同时我们发现只有300,于是考虑在上做优化。
既然要在上考虑优化,那么我们可以考虑将所有相等的v一起考虑。不难发现,在同一个中,我们一定可以贪心的选最大的几个v,即决策单调。
同时,在同一个中,我们不难发现当i,j之差为c[i]时转移一定最优。所以我们可以考虑对于mod 相等的数一起计算。
我们不难看出这里的决策是单调的。
但是我们并不能用单调队列维护(貌似?),于是我们可以考虑分治。(具体见代码)
- 代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e6+5,M=5e4+5,C=310;
int c[N],v[N];
int n,k,mxc,ind;
ll dp[C][M];
vector<ll>bag[C],buc[C];
bool cmp(const int a,const int b){return a>b;}
int table[N];
ll cal(int id,int lstpos,int now){
int num=(now-lstpos)/id;
if(num>(signed)bag[id].size()-1)return -1;
return dp[id-1][lstpos]+bag[id][num];
}
void solve(int id,int l,int r,int pl,int pr){//"pl,pr为决策点的范围
int mid=(l+r)>>1;int pos=0;ll maxv=0;
for(int i=pl;i<=min(mid,pr);i++){
ll val=cal(id,table[i],table[mid]);
if(val>maxv)maxv=val,pos=i;
}
if(l==r){
dp[id][table[l]]=maxv;
return;
}
solve(id,l,mid,pl,pos);
solve(id,mid+1,r,pos,pr);
}
int main()
{
scanf("%d%d",&n,&k);
for(int i=1;i<=n;i++){
scanf("%d%d",&c[i],&v[i]);
buc[c[i]].push_back(v[i]);
mxc=max(mxc,c[i]);
}
for(int i=1;i<=mxc;i++){
sort(buc[i].begin(),buc[i].end(),cmp);
bag[i].push_back(0);
ll now=0;
for(int j=0;j<(signed)buc[i].size();j++){
now+=buc[i][j];
bag[i].push_back(now);
}
}
for(int i=1;i<=mxc;i++){
for(int j=0;j<=i-1;j++){//"考虑mod i=j的转移
table[ind=1]=j;
while(table[ind]+i<=k){
table[ind+1]=table[ind]+i;
++ind;
}
solve(i,1,ind,1,ind);
}
}
for(int i=1;i<=k;i++){
printf("%lld ",dp[mxc][i]);
}
}