码迷,mamicode.com
首页 > 其他好文 > 详细

Codeforces 609D 被二分教做人

时间:2015-12-24 10:36:01      阅读:192      评论:0      收藏:0      [点我收藏+]

标签:

传送门:http://codeforces.com/problemset/problem/609/D

(如需转载,请注明出处,谢谢O(_)O

 

题意:

Nura想买k个小玩意,她手上有 s 个burles(一种货币),有m个小玩意供她选择购买,但每个小玩意只能用dollars或者pounds来购买,所以每次购买的时候Nura都要通过汇率将她手上的burles换成dollars或者pounds,而每一天的汇率又不一样,给出n天,并且这n天中burles换成dollars和pounds的比率,问是否能在这n天中用手上的burles买下k个小玩意,如果不能,输出-1;如果能,输出最小的天数(即能使得Nura买下k个小玩意的最少天数),并在接下来的m行中,依次输出两个数字,分别是买下的小玩意的编号(按给出的顺序编号)以及买下该小玩意的日期(即第几天)。——在同一天中可以买任意多个小玩意。

 

解题思路与分析:

注意到数据范围是2e5,而显然需要通过某种方式来比较“天数”,直接枚举肯定很虚,所以要用到二分。

(这里给出同学写的二分的正确姿势:

int L,R,M;

while(R-L>1){

       M=((R-L)>>1)+L;

       if() R=M;

       else L=M;

}

确定了用二分来枚举天数之后,就需要确定二分里面的内容。因为一天可以买多个,所以显然应该找兑换率最高的一天,即区间最小值,这里用了ST算法,O(nlogn)预处理,O(1)查询——获得了区间里burles兑换dollars和pounds最“划算”的一天后,就是确定买下k个小玩意的最小花费了,这里没有想到更简便的方法,只能用了O(mlogm)的预处理(排序),每次O(k)获取花费。用结构体存储小玩意的type,cost以及num(编号,后面输出用到),然后排序——重载小于号,先按type排,再按cost排,记录type==2的第一个小玩意对应的下标ter,之后只需要每次计算的时候比较一下,就能保证获取最小花费了(细节见代码)——获取最小花费后,将之与s比较一下即可知该区间是否可行。

 

代码实现过程与反思:

感觉基本上坑被踩了个尽。。

1、计算最小花费的时候,会造成int溢出,要用long long。

2、不是坑的坑:原题output部分中的”number of gadget”,是指小玩意的编号,不是数目(gadget没有s),醉。

4、细节:计算最小花费的时候,while循环应为j<m而不为j<n(j为ter为起点的下标,i从0开始),又wa一发。。

3、二分的时候,因为while中的是R-L>1,所以当n为1时,将直接跳过二分判断。并且,如果存在可行的答案,其必然为二分循环结束后的L或者R,先判L,如果L不行就判断R;如果都不行,说明不存在正确结果。这里又wa了几发,,被二分教做人。

 

代码如下:

技术分享
  1 #include<iostream>
  2 #include<cstdio>
  3 #include<algorithm>
  4 #include<cstring>
  5 using namespace std;
  6 typedef long long ll;
  7 const int N=2e5+10,M=15;
  8 struct gadget{
  9     int type,cost,num;
 10     bool operator < (const gadget g) const{
 11         return type==g.type?cost<g.cost:type<g.type;
 12     }
 13 }G[N];
 14 int n,m,k,s,ter,a[N],b[N],da[N][M],db[N][M];
 15 void init(){
 16     for(int i=0;i<n;i++) da[i][0]=a[i],db[i][0]=b[i];
 17     for(int j=1;(1<<j)<=n;j++)
 18         for(int i=0;i+(1<<j)-1<n;i++){
 19             da[i][j]=min(da[i][j-1],da[i+(1<<(j-1))][j-1]);
 20             db[i][j]=min(db[i][j-1],db[i+(1<<(j-1))][j-1]);
 21         }
 22 }
 23 int RMQ(int L,int R,int d[N][M]){
 24     int k=0;
 25     while((1<<(k+1))<=R-L+1) k++;
 26     return min(d[L][k],d[R-(1<<k)+1][k]);
 27 }
 28 bool check(ll p1,ll p2){
 29     int cnt=0;
 30     ll tot=0;
 31     int i=0,j=ter;
 32     while(j<m){
 33         if(i==ter||cnt==k) break;
 34         if(G[i].cost*p1<=G[j].cost*p2)
 35             tot+=G[i++].cost*p1;
 36         else tot+=G[j++].cost*p2;
 37         cnt++;
 38     }
 39     if(cnt<k){
 40         if(i<ter) swap(i,j),swap(p1,p2);
 41         while(cnt<k) tot+=p2*G[j++].cost,cnt++;
 42     }
 43     return tot<=s;
 44 }
 45 int main(){
 46     //freopen("in.txt","r",stdin);
 47     while(~scanf("%d%d%d%d",&n,&m,&k,&s)){
 48         for(int i=0;i<n;i++)
 49             scanf("%d",a+i);
 50         for(int i=0;i<n;i++)
 51             scanf("%d",b+i);
 52         ter=0;
 53         for(int i=0;i<m;i++){
 54             scanf("%d%d",&G[i].type,&G[i].cost);
 55             if(G[i].type==1) ter++;
 56             G[i].num=i+1;
 57         }
 58         init();
 59         sort(G,G+m);
 60         bool flag=false;
 61         int L=0,R=n-1,mid;
 62         ll p1,p2;
 63         while(R-L>1){
 64             mid=((R-L)>>1)+L;
 65             p1=RMQ(0,mid,da),p2=RMQ(0,mid,db);
 66             if(check(p1,p2)) R=mid;
 67             else L=mid;
 68         }
 69         p1=RMQ(0,L,da),p2=RMQ(0,L,db);
 70         if(check(p1,p2)) flag=true;
 71         else{
 72             p1=RMQ(0,R,da),p2=RMQ(0,R,db);
 73             if(check(p1,p2)) flag=true;
 74         }
 75         if(flag){
 76             int d1,d2;
 77             for(int i=0;i<n;i++) if(a[i]==p1){
 78                 d1=i+1;break;
 79             }
 80             for(int i=0;i<n;i++) if(b[i]==p2){
 81                 d2=i+1;break;
 82             }
 83             printf("%d\n",max(d1,d2));
 84             int cnt=0,tot=0;
 85             int i=0,j=ter;
 86             while(j<m){
 87                 if(i==ter||cnt==k) break;
 88                 if(G[i].cost*p1<=G[j].cost*p2){
 89                     cnt++;
 90                     printf("%d %d\n",G[i++].num,d1);
 91                 }
 92                 else{
 93                     cnt++;
 94                     printf("%d %d\n",G[j++].num,d2);
 95                 }
 96             }
 97             if(cnt<k){
 98                 if(i<ter) swap(d1,d2),swap(i,j);
 99                 while(cnt<k) printf("%d %d\n",G[j++].num,d2),cnt++;
100             }
101         }
102         else puts("-1");
103     }
104     return 0;
105 }
View Code

 

Codeforces 609D 被二分教做人

标签:

原文地址:http://www.cnblogs.com/names-yc/p/5072126.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!