zoj3606

  1 /*
  2 题意:售货员每隔w分钟就会睡觉,如果售货员睡着了那么顾客会叫醒她但是不会买东西,
  3 有n个客人会不同时间来,并且售货员卖给第i的客人的价格为p[i],并且售货员会在第k次卖
  4 出1+(k-1)%3个面包,求问最小的w使平均每次卖出的面包的价格最大即总收入/卖的次数;
  5 
  6 分析:如果w小于最小的时间间隔,那么售货员不会卖出一个面包显然不是最优的,
  7 当w>某一个时间间隔,那么会买面包的顾客都是时间间隔小于w的,
  8 显然最后答案肯定是某一个顾客的时间间隔,枚举要O(n^2),肯定超时;
  9 我们知道当w按顾客时间间隔递增,那么前面会买面包的顾客后面还是同样会买的,
 10 改变的只是卖的面包的个数,
 11 
 12 现在要完成的工作就是 单点更新,然后按照1,2,3,1,2,3的个数卖,求总收入和总买的次数
 13 
 14 我们可以通过线段树来完成这个工作,
 15 定义c[N<<2][3]和pos[N<<2];
 16 c[i][0]表示线段i起始位置顾客买1个面包,总的收入;
 17 c[i][1]表示线段i起始位置顾客买2个面包,总的收入;
 18 c[i][2]表示线段i起始位置顾客买3个面包,总的收入;
 19 pos[i]表示线段i里买面包的顾客的人数 
 20 
 21 这样就可以通过c[rt<<1][]和c[rt<<1|1][],来递推c[rt][];
 22 具体见代码;可以手推枚举一下;  
 23 trick:读入的时间不是按照顺序来的,要先排序,这个trick虽然很常见
 24 但是如果一不小心还是很容易掉进去不能自拔的;
 25  
 26 
 27 */
 28 #include<cstdio> 
 29 #include<cstring>
 30 #include<cstdlib>
 31 #include<iostream>
 32 #include<algorithm>
 33 #include<vector>
 34 #include<map>
 35 #define lson l,m,rt<<1
 36 #define rson m+1,r,rt<<1|1
 37 using namespace std;
 38 typedef long long LL;
 39 const int N=100000+10;
 40 const double eps=1e-10;
 41 LL c[N<<2][3];
 42 int pos[N<<2];
 43 vector<int> x,g[N];
 44 int n,n1;
 45 struct node{
 46     int pi,ti;
 47     bool operator < (const node&p)const{
 48         return ti<p.ti;
 49     }
 50 }nd[N];
 51 void init(){
 52     x.clear();
 53     for (int i=1;i<=n;i++){
 54         scanf("%d",&nd[i].pi);
 55     }    
 56     nd[0].ti=0;
 57     for (int  i=1;i<=n;i++){
 58         scanf("%d",&nd[i].ti);
 59     }
 60     sort(nd+1,nd+n+1);
 61     for (int i=1;i<=n;i++){
 62         x.push_back(nd[i].ti-nd[i-1].ti);
 63     }
 64     sort(x.begin(),x.end());
 65     n1=unique(x.begin(),x.end())-x.begin();
 66     for (int i=0;i<=n1;i++) g[i].clear();
 67     for (int i=1;i<=n;i++){
 68         int tmp=lower_bound(x.begin(),x.begin()+n1,nd[i].ti-nd[i-1].ti)-x.begin();
 69         g[tmp].push_back(i);
 70     }
 71     //cout<<"*** "<<endl;
 72     //for (int i=0;i<n1;i++) cout<<x[i]<<" ";cout<<endl;
 73 }
 74 void pushup(int rt){
 75     int t;
 76     pos[rt]=pos[rt<<1]+pos[rt<<1|1];
 77     t=pos[rt<<1]%3;
 78     for (int i=0;i<3;i++)
 79         c[rt][i]=c[rt<<1][i]+c[rt<<1|1][(t+i)%3];
 80     
 81 }
 82 void update(int L,int l,int r,int rt){
 83     if (l==r){
 84         c[rt][0]=nd[l].pi;
 85         c[rt][1]=nd[l].pi*2;
 86         c[rt][2]=nd[l].pi*3;
 87         pos[rt]=1;
 88         return;
 89     }
 90     int m=(l+r)>>1;
 91     if (L<=m) update(L,lson);
 92     else update(L,rson);
 93     pushup(rt);
 94 }
 95 void work(){
 96     LL ret1=0,ret2=0,ret3;
 97     memset(c,0,sizeof(c));
 98     memset(pos,0,sizeof(pos));
 99     for (int i=0;i<n1;i++){
100         int sz=g[i].size();
101         if (sz!=0){
102             for (int j=0;j<sz;j++){
103                 int v=g[i][j];
104                 update(v,1,n,1);
105             }
106             //double tmp=(double)c[1][0]/pos[1];
107         //    cout<<i<<" ** "<<c[1][0]<<" "<<pos[1]<<endl;
108             if (ret1==0 || c[1][0]*ret2>ret1*pos[1]) {
109                 ret1=c[1][0];
110                 ret2=pos[1];
111                 ret3=x[i];
112             }
113         }
114     }    
115     printf("%.6lf %.6lf\n",(double)ret3+eps,(double)ret1/ret2+eps);
116 }
117 int main(){
118     int T;scanf("%d",&T);
119     while (T--){
120         scanf("%d",&n);
121         init();
122         work();    
123     }
124     return 0;
125 }

 

转载于:https://www.cnblogs.com/Rlemon/archive/2013/05/18/3085437.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值