1:如果有个顾客和上一个顾客间的时间间隔超过了w,这个顾客就不糊买东西,而与上一个顾客来的时间间隔小于等于w的顾客肯定能买到面包
所以我们只需枚举每个时间间隔既可,答案肯定就是某个时间间隔,一旦时间间隔定了,那能卖的面包数以及买到东西的顾客数也就定了
2:买到面包的数量问题,由题目给出的式子可得,卖出面包数量的序列 为1 2 3 1 2 3.。。。所以如果知道了某个人买了几个面包,那么可以
推算出接下来第x个人买了几个面包,因为最多也只有三种情况,所以把三种情况的结果都保存一下,就用到了三个线段树,其实就是线段树的域开个二维数组
线段树的域:
sum[rt]:记录当前节点的区间内共有几个顾客
pp[rt][3]:记录当区间最左边的人分别买了 1 2 3个面包时总的销售额
那么我们可以通过线段树将这个结果传递上去
关键代码:
for(int i=0;i<3;i++)
pp[x][i]=pp[x<<1][i]+pp[x<<1|1][(sum[x<<1]+i)%3];
知道了左子树第一个人买的面包个数,和左子树的人数,自然就可以推出右子树第一个人买的面包个数,三种情况都记录一下,然后再传递上去
最后的结果是pp[1][0],因为第一个人肯定只买了一个面包;
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#define lson l , m , rt << 1
#define rson m + 1, r, rt << 1 | 1
#define maxn 100010
using namespace std;
//sum[]表示在这个区间里面来了多少人
int sum[maxn << 2];
//p表示在这个区间里面卖了多少钱
double p[maxn << 2][3];
struct customer{
int id,t;
double price;
bool operator < (const customer &cmp) const{
return t < cmp.t;
}
}cusa[maxn],cusb[maxn];
void update(int pos, int l, int r, int rt){
//pos表示是第几个来的。
sum[rt] ++;
if(l == r){
for(int i = 0; i < 3; i ++)
p[rt][i] = 1.0 * (i + 1) * cusa[pos].price;//
return;
}
int m = (l + r) >> 1;
if(pos <= m) update(pos,lson);
else update(pos,rson);
for(int i = 0; i < 3; i ++)
p[rt][i] = p[rt << 1][i] + p[rt << 1 | 1][(sum[rt << 1] + i)%3];
}
int t,n;
int main(){
scanf("%d",&t);
while(t --){
scanf("%d",&n);
for(int i = 1; i <= n; i ++){
scanf("%lf",&cusa[i].price);
} for(int i = 1; i <= n; i ++){
scanf("%d",&cusa[i].t);
}
//先按来的时间排,并用id记录这位顾客是第几位顾客,用t记录他与前一位顾客的时间间隔
sort(cusa + 1, cusa + 1 + n);
cusa[0].t = 0;
for(int i = 1; i <= n; i ++){
cusb[i].t = cusa[i].t - cusa[i - 1].t;
cusb[i].id = i;
}
memset(sum,0,sizeof(sum)); memset(p,0,sizeof(p));
sort(cusb + 1, cusb + 1 + n);
double ans_aver= 0,ans_w,tmp;
for(int i = 1,j = 1; i <= n; i = j){
//枚举时间间隔,相同间隔的一起处理,因为时间间隔相同的才能买到面包
while(cusb[i].t == cusb[j].t && j <= n){
update(cusb[j].id,1,n,1); j ++;
}
tmp = p[1][0] / (sum[1] * 1.0);
if(ans_aver < tmp){
ans_aver = tmp;
ans_w = cusb[i].t;
}
}
printf("%.6lf %.6lf\n",ans_w,ans_aver);
}
return 0;
}