CCF-集合竞价(开盘价定为买价,1e8*5000--long long)

问题描述  某股票交易所请你编写一个程序,根据开盘前客户提交的订单来确定某特定股票的开盘价和开盘成交量。

该程序的输入由很多行构成,每一行为一条记录,记录可能有以下几种:

1. buy p s 表示一个购买股票的买单,每手出价为p,购买股数为s。

2. sell p s 表示一个出售股票的卖单,每手出价为p,出售股数为s。

3. cancel i表示撤销第i行的记录。

如果开盘价为p0,则系统可以将所有出价至少为p0的买单和所有出价至多为p0的卖单进行匹配。因此,此时的开盘成交量为出价至少为p0的买单的总股数和所有出价至多为p0的卖单的总股数之间的较小值。

你的程序需要确定一个开盘价,使得开盘成交量尽可能地大。如果有多个符合条件的开盘价,你的程序应当输出最高的那一个。输入格式  输入数据有任意多行,每一行是一条记录。保证输入合法。股数为不超过108的正整数,出价为精确到恰好小数点后两位的正实数,且不超过10000.00。输出格式  你需要输出一行,包含两个数,以一个空格分隔。第一个数是开盘价,第二个是此开盘价下的成交量。开盘价需要精确到小数点后恰好两位。样例输入buy 9.25 100

buy 8.88 175

sell 9.00 1000

buy 9.00 400

sell 8.92 400

cancel 1

buy 100.00 50样例输出9.00 450评测用例规模与约定  对于100%的数据,输入的行数不超过5000。

解题思路:
(1)、开盘价一定是买价。由题意得,买价>=开盘价&&卖价<=开盘价时,交易量才有效。举个例子就很清晰:出价100买500股,出价50卖500股。若开盘价p0为50-99元,交易量为500,但是若p0为100,交易量也为500。由题意得p0要尽可能高,故开盘价p0一定是buy中的价格。
(2)将价钱一起由大到小排序,买与卖做不同的标记(bos)。由大到小将买价进行累加,每加一次都保存在当前价格的交易量内。再由小到大将出售价累加。这样做的目的时在查找时无需重复计算交易量。
(3)遍历买价,顺序由大到小,所以从0开始一定是价钱最高,交易量最大。交易量为min(买入量,卖出量),都再结构体的trade中。

**另外,一定注意,交易量为1e8,若输入500次,需要longlong保存。(要不一直80分)。**
#include<iostream>
#include<map>
#include<cstdio>
#include<vector>
#include<cmath>
#include<algorithm>
using namespace std;
typedef struct node{
 int bos;//1为买,0为卖 ,-1为删除 
 double p;
 long long s;
 long long  trade;
 bool operator < (const node & t) const{
  if(p!=t.p){
   return p>t.p;
  }
  else {
   return bos>t.bos;
  }
 } 
}Nod;
map<int ,Nod> ma;
vector<Nod> vec;
int main(){
 string com;
 int hang=0;
 while(cin>>com){
  hang++;
  if(com=="buy"){
   long long s;
   double p;
   cin>>p>>s;
   ma[hang].p=p;
   ma[hang].s=s;
   ma[hang].bos=1;
  }
  else if(com=="sell"){
   long long s;
   double p;
   cin>>p>>s;
   ma[hang].p=p;
   ma[hang].s=s;
   ma[hang].bos=0;
  }
  else if(com=="cancel"){
   int h;
   cin>>h;
   ma[h].bos=-1;
  }
 }
 map<int ,Nod>::iterator it;
 for(it =ma.begin();it!=ma.end();it++){//将删除操作后的值存入向量中,这样麻烦,没有必要。
  if(it->second.bos!=-1) 
   vec.push_back(it->second);
 }
 sort(vec.begin(),vec.end());
 long long sum=0;
 for(int i=0;i<vec.size();i++){//从大到小,对买入量进行累加,每次累加都要保存
  if(vec[i].bos==1){
   sum+=vec[i].s;
   vec[i].trade=sum;
  }
 }
 sum=0;
 for(int i=vec.size()-1;i>=0;i--){//从小到大,因为卖价越低,卖出去的可能越大。
  if(vec[i].bos==0){
   sum+=vec[i].s;
   vec[i].trade=sum;
  }
 }
 long long  max_trade=0;
 double res_p=0;
 for(int i=0;i<vec.size();i++){
  long long  tmp_trade=0;//这个longlong容易忘,注意!!
  if(vec[i].bos==1){
   for(int j=i+1;j<vec.size();j++){
    if(vec[j].bos==0){
     tmp_trade=min(vec[i].trade,vec[j].trade);//交易量就是买入量和卖出量的最小值(公共部分)。
     break;
    }
   }
   if(max_trade<tmp_trade){
    res_p=vec[i].p;
    max_trade=tmp_trade; 
   }
  }
 }
 printf("%.2lf %lld",res_p,max_trade);
 return 0;
} 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值