[loj6039][雅礼集训 2017 Day5]珠宝——决策单调性+分治 大佬们的博客 Some Links

版权声明:欢迎大家转载,转载请标明出处。 https://blog.csdn.net/ylsoi/article/details/82711978

###题目大意:
Miranda 准备去市里最有名的珠宝展览会,展览会有可以购买珠宝,但可惜的是只能现金支付,Miranda 十分纠结究竟要带多少的现金,假如现金带多了,就会比较危险,假如带少了,看到想买的右买不到。展览中总共有 N N 种珠宝,每种珠宝都只有一个,对于第 i i 种珠宝,它的售价为 C i C_i ​万元,对 Miranda 的吸引力为 V i V_i ​​ 。
Miranda 总共可以从银行中取出 K K 万元,现在她想知道,假如她最终带了 i i 万元去展览会,她能买到的珠宝对她的吸引力最大可以是多少?
###思路:
每个物品的重量很小,于是按照重量分类,对于同一个重量里面的物品一起考虑。
不难发现,贪心的选择物品,对于同一个重量,选择的物品一定是按照价值从大到小排序的一个前缀。
于是对于每一种重量的决策,体积也按照剩余类分类,不同剩余类的dp分开考虑,此时dp可以看成是连续的。
因为选择的是一个前缀,并且前缀和的斜率不断减小,不难发现满足决策单调性,简单地证明一下:
i < j i<j i i 的决策点为 p 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] ,即 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] ,又因为有 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] ,所以有 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]
于是直接分治优化决策单调性就好了,所谓分治大概就是不断地确定一个区间中点的决策点,这样以后对于左区间和右区间便各自拥有了上界和下界,然后不断地递归就好了。
时间复杂度 Θ ( 300 m log m ) \Theta(300m\log{m})

#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;
}

猜你喜欢

转载自blog.csdn.net/ylsoi/article/details/82711978
今日推荐