ZOJ 3606 Lazy Salesgirl 线段树

题意:有一个卖面包的姑娘,如果过了w分钟仍旧没有客人来的话,他就会睡着,如果客人在他睡着的时候来的话,客人会把她叫醒,然后离开。

每个客人会以不同的价格买面包,姑娘会买给第i个客人(i-1)%3+1块面包,求在收到的钱做多的情况下的最小的w.

做法:唉,没想到....只能看大神的。10W个人用线段树是没错的。要求最小的w,可是为了可以让客人买到面包,这里的w的值是离散的,即相邻两个客人之间的间隔。一开始还脑残的以为可以2分答案...

先对每个客人根据到来的时间进行排序,然后算出每个客人的w,然后再根据w排序(只要客人的w相同,枚举到这个时间间隔是,这个客人就一定可以买到东西)。

建立线段树是,节点记录的是现在的区间中的客人数,还有现在可以在各种购买量下获得的利润。

还有一点时,如果a客人买了x片面包,a+1就可以买(x+1)%3+1片,这个在两区间合并时注意,见pushup

(a+b)%mod=(a%mod+b%mod)%mod 唉,傻了...

#include<cstdio>
#include<cstring>
#include<algorithm>
#define LL long long
using namespace std;
const int LMT=100003;
const int WEI=3;
#define left l,m,x<<1
#define right m+1,r,x<<1|1
double p[LMT];
int sum[LMT<<2];
LL get[WEI+1][LMT<<2];
double ansg,anst;
/*************
节点记录了当区间最左侧的购买序列为I使整个区间可以获得的
钱,取余数记得这种分割法啊。。。
******/
struct person
{
	int t,p;
	bool operator<(const person &y)const
	{
		return t<y.t;
	}
}per[LMT];
struct ma
{
	int id,w;
	bool operator<(const ma &y)const
	{
		return w<y.w;
	}
}man[LMT];
void init(void)
{
	ansg=anst=0;
	memset(sum,0,sizeof(sum));
	memset(get,0,sizeof(get));
}
void pushup(int x)
{
	sum[x]=sum[x<<1]+sum[x<<1|1];
	int tem,i;
	for(i=1;i<=WEI;i++)
	{
		tem=(i+sum[x<<1]-1)%WEI+1;
		get[i][x]=get[i][x<<1]+get[tem][x<<1|1];
	}
}
void update(int pos,LL p,int l,int r,int x)
{
	if(l==r)
	{
		sum[x]++;
		for(int i=1;i<=WEI;i++)
			get[i][x]=i*p;
		return;
	}
	int m=(l+r)>>1;
	if(pos<=m)update(pos,p,left);
	if(pos>m)update(pos,p,right);
	pushup(x);
}
int main(void)
{
	int T,n,i,j;
	double tem;
	scanf("%d",&T);
	while(T--)
	{
		init();
		scanf("%d",&n);
		for(i=0;i<n;i++)scanf("%d",&per[i].p);
		for(i=0;i<n;i++)scanf("%d",&per[i].t);
		sort(per,per+n);
		man[0].w=per[0].t;
		man[0].id=0;
		for(i=1;i<n;i++)
		{
			man[i].w=per[i].t-per[i-1].t;
			man[i].id=i;
		}
		sort(man,man+n);
		for(i=0;i<n;)
		{
			j=i;
			while(j<n&&man[i].w==man[j].w)
			{
				update(man[j].id,per[man[j].id].p,0,n-1,1);
				j++;
			}
			tem=get[1][1]*1.0/sum[1];
			if(ansg<tem)
			{
				ansg=tem;
				anst=man[i].w;
			}
			i=j;
		}
		printf("%.6lf %.6lf\n",anst,ansg);
	}
	return 0;
}


 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值