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;

}

你可能感兴趣的:(lazy)