UESTC 1558 Charitable Exchange

题目链接:http://acm.uestc.edu.cn/problem.php?pid=1558

题目大意:star一开始有1元,他可以通过一次交换(v,r,t)来增加自己的资金,v(1~10^9)表示得到的资金,r(1~10^9)表示交换耗去的资金,t(1~10^9)表示该次交换耗费的时间,给定n(1~10^5)种交换,star最后至少有m(1~10^9)元,求达到要求的最小时间.

思路:这有点像背包问题,和背包不同在于,他的取是有限制的,必须r不可以超过star当前的资金数,但是状态方程是类似的.dp[i]=min(dp[j])
+t[i],i第i种交换获得的资金数,j同理且j<i,t[i]则为第i次交换所耗费的时间,显然dp[]存的就是时间.难点在于获取min(dp[j]).(1)资金数的范围很广,离散一下,不然数组开不下.(2)快速获取数组中某一段的min值,显然可以用线段树.

代码:

#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <ctype.h>
#include <math.h>
#include <time.h>
#include <stack>
#include <queue>
#include <map>
#include <set>
#include <vector>
#include <string>
#include <iostream>
#include <algorithm>
using namespace std;

//#define ull unsigned __int64
//#define ll __int64
#define ull unsigned long long
#define ll long long
#define son1 New(p.xl,xm,p.yl,ym),(rt<<2)-2
#define son2 New(p.xl,xm,min(ym+1,p.yr),p.yr),(rt<<2)-1
#define son3 New(min(xm+1,p.xr),p.xr,p.yl,ym),rt<<2
#define son4 New(min(xm+1,p.xr),p.xr,min(ym+1,p.yr),p.yr),rt<<2|1
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
#define middle (l+r)>>1
#define MOD 1000000007
#define esp (1e-8)
const int INF=0x3FFFFFFF;
const ll LINF=0x3FFFFFFFFFFFFFFF;
const double DINF=10000.00;
//const double pi=acos(-1.0);
const int N=100010;
int n,m,tot;
ll M,X[N<<1],mmin[N<<3],cov[N<<3];
struct node{
	ll v,r,t;
	void write(){
		scanf("%lld%lld%lld",&v,&r,&t);
		X[m++]=v,X[m++]=r;
	}
	bool operator < (const node& tmp)const{
		return r < tmp.r;
	}
}a[N];

ll min(ll x,ll y){return x<y? x:y;}

int bs(ll key,int size,ll A[]){
	int l=0,r=size-1,mid,ret=0;
	while(l<=r){
		mid=middle;
		if(key>A[mid]) l=mid+1;
		else if(key<=A[mid]) r=(ret=mid)-1;
	}
	return ret;
}

void Build(int l,int r,int rt){
	mmin[rt]=LINF;
	if(l==r) return;
	int mid=middle;
	Build(lson),Build(rson);
}

void PushUp(int rt){
	mmin[rt]=min(mmin[rt<<1],mmin[rt<<1|1]);
}

void Update(int l,int r,int rt,int p,ll c){
	if(l==r){mmin[rt]=min(mmin[rt],c);return;}
	int mid=middle;
	if(p<=mid) Update(lson,p,c);
	else Update(rson,p,c);
	PushUp(rt);
}

ll Query(int l,int r,int rt,int L,int R){
	if(L<=l && r<=R) return mmin[rt];
	int mid=middle;
	ll ret=LINF;
	if(L<=mid) ret=min(ret,Query(lson,L,R));
	if(mid<R) ret=min(ret,Query(rson,L,R));
	return ret;
}

void init(){
	scanf("%d%lld",&n,&M);
	int i;
	for(i=m=0;i<n;i++) a[i].write();
	sort(a,a+n);sort(X,X+m);
	for(i=tot=1;i<m;i++)if(X[i]!=X[i-1])X[tot++]=X[i];
	m=tot-1;Build(0,m,1);
}

void sof(){
	if(a[0].r>1) puts("-1");
	else{
		int i;
		ll tmp_T;
		Update(0,tot,1,0,0);
		for(i=0;i<n;i++){
			tmp_T=Query(0,m,1,bs(a[i].r,tot,X),m);
			if(tmp_T==LINF) break;
			Update(0,m,1,bs(a[i].v,tot,X),tmp_T+a[i].t);
		}
		tmp_T=Query(0,m,1,bs(M,tot,X),m);
		if(tmp_T==LINF) puts("-1");
		else printf("%lld\n",tmp_T);
	}
}

int main(){
	//freopen("1.in","r",stdin);
	//freopen("1.out","w",stdout);
	int T,cas=0;scanf("%d",&T);for(cas=1;cas<=T;cas++){
		init();
		printf("Case #%d: ",cas);
		sof();
	}
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值