zoj zju 3606 Lazy Salesgirl

题意:有一个售货员,n个顾客,卖给 i 这个顾客的价格是pi,i 顾客来买东西的时刻为 ti

如果有w的时间段没人来买东西,售货员就会睡着,下一个顾客来时会叫醒她,但是不买东西

售货员会卖给第i个来(相对顺序)的顾客 1 + ((i - 1) mod 3)的数量的面包 即 1 2 3 中的一个

问使得平均的销售额最大的最小w以及此时的平均销售额是多少( 总的销售额/顾客的个数)

 

做法:我觉得关键是要抓住题目的特点,深挖下去,售货员每隔w时间会睡着,那就意味着,

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],因为第一个人肯定只买了一个面包;

View Code
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define lson l,m,x<<1
#define rson m+1,r,x<<1|1
const int maxn = 100010;
int sum[maxn<<2];
double pp[maxn<<2][3];
struct node{
    int id,len,num,tt;
    bool operator < (const node &cmp) const{
        return tt<cmp.tt;
    }
}a[maxn],cnt[maxn];
void update(int pos,int l,int r,int x){
    sum[x]++;
    if(l==r){
        for(int i=0;i<3;i++)  pp[x][i]=1.0*(i+1)*a[pos].num;
        return ;
    }
    int m=(l+r)>>1;
    if(pos<=m) update(pos,lson);
    else update(pos,rson);
    for(int i=0;i<3;i++)
        pp[x][i]=pp[x<<1][i]+pp[x<<1|1][(sum[x<<1]+i)%3];
}
int main(){
    int t,n,i,j;
    scanf("%d",&t);
    while(t--){
        scanf("%d",&n);
        for(i=1;i<=n;i++)  scanf("%d",&a[i].num);
        for(i=1;i<=n;i++)  scanf("%d",&a[i].tt);
        sort(a+1,a+n+1);
        a[0].tt=0;
        for(i=1;i<=n;i++) {
            cnt[i].tt=a[i].tt-a[i-1].tt;
            cnt[i].id=i;
        }
        memset(sum,0,sizeof(sum));
        memset(pp,0,sizeof(pp));
        sort(cnt+1,cnt+n+1);
        double aver_ans=0,w_ans;
        for(i=1,j=1;i<=n;i=j){
            while(cnt[j].tt==cnt[i].tt && j<=n) //j<=n 
                update(cnt[j].id,1,n,1);
                j++;
            }
            double tmp=pp[1][0]*1.0/sum[1];
            if(tmp>aver_ans){
                aver_ans=tmp;
                w_ans=cnt[i].tt;
            }
        } 
        printf("%.6lf %.6lf\n",w_ans,aver_ans);
    }
    return 0;
}
posted @ 2012-04-28 10:13  Because Of You  Views(1031)  Comments(0Edit  收藏  举报