CCF201412-3 集合竞价

问题描述

  某股票交易所请你编写一个程序,根据开盘前客户提交的订单来确定某特定股票的开盘价和开盘成交量。该程序的输入由很多行构成,每一行为一条记录,记录可能有以下几种:

  • buy p s 表示一个购买股票的买单,每手出价为p,购买股数为s。
  • sell p s 表示一个出售股票的卖单,每手出价为p,出售股数为s。
  • 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

思路

写在前面的坑点提醒:一开始还是没有理解好题目,我的做法是直接枚举输入的所有价格,然后取成交量最大的那一个,对于cancel操作,其实题意描述有点不清,我想着有可能有撤销多级操作的现象,就记录了每个cancel所对应的操作,然后逐级向上进行撤销,┗|`O′|┛ ~~最后结果WA了,而且代码写得很丑。。。。。。
后来在参考别人的题解时才对题目有了正确的理解,首先cancel只能撤销一级操作,其次,最终开盘价的结果应该是买单价格之一。理解到这儿,这个题差不多就可以解决了,然后在看别人blog的过程中,学习了两种比较好的处理方法,分别是利用优先级队列数组排序的做法,下面来简要整理一下:
解法一:
首先将买单价格压入大根堆,将卖单价格压入小根堆,并为需要撤销的操作打上标记,在取堆顶元素时注意首先要将撤销的订单弹出,然后根据买单价格大于等于卖单价格以及开盘成交量为买单总股数和相应的卖单总股数之间的较小值这一条件来维护两个堆,直至出现堆空或大根堆堆顶元素小于小根堆堆顶元素时结束操作。
解法二:
将买单信息和卖单信息(存储的同时计算卖单成交量的总和Sums)分别存入数组buy,sell,并将两数组按照订单价格的降序排序,然后遍历buy数组,对于每一个遍历到的买单信息,搜索sell数组,将卖单价格大于当前买单价格的卖单所对应的成交量从卖单总成交量中减去,最后取买单和卖单成交量的较小值作为当前开盘价所对应的成交量,所有成交量中的最大值即为最终结果。

代码实现

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

struct order{
	int idex;
	int type;
	double price;
	ll count;
	order(){}
	order(int ii,int tt,double pp,int cc){idex=ii;type=tt;price=pp;count=cc;}
	bool operator<(const order& b) const{
		if(type==1)
			return price<b.price;
		if(type==2)
			return price>b.price;
	}
};

bool cancel[5010];
priority_queue<order> buy,sell;

int main()
{
	string op;
	memset(cancel,0,sizeof(cancel));
	int i=1;
	while(cin>>op){
		double a;ll b;
		if(op[0]=='b'){
			cin>>a>>b;
			buy.push(order(i,1,a,b));
		}
		else if(op[0]=='s'){
			cin>>a>>b;
			sell.push(order(i,2,a,b));
		}
		else{
			int no;
			cin>>no;
			cancel[no]=true;
		}
		i++;
	}
	double p=0;ll ans=0;	
	order b,s;
	while(!buy.empty()&&!sell.empty()){		
		while(!buy.empty()){
			b=buy.top();
			if(cancel[b.idex])
				buy.pop();
			else
				break;
		}
		while(!sell.empty()){
			s=sell.top();
			if(cancel[s.idex])
				sell.pop();
			else
				break;			
		}
		if(buy.empty()||sell.empty())
			break;
		if(b.price>=s.price){
			p=b.price;
			ans+=min(b.count,s.count);
			if(b.count==s.count){
				buy.pop();
				sell.pop();
			}
			else if(b.count>s.count){
				b.count-=s.count;
				buy.pop();
				buy.push(b);
				sell.pop();
			}
			else{
				buy.pop();
				s.count-=b.count;
				sell.pop();
				sell.push(s);
			}
		}
		else
			break;		
	}
	printf("%.2lf %lld\n",p,ans);
	return 0;
}
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

struct order{
	int idex;
	int type;
	double price;
	ll count;
	order(){}
	order(int ii,int tt,double pp,int cc){idex=ii;type=tt;price=pp;count=cc;}
	bool operator<(const order& b) const{
		return price>b.price;
	}
};

bool cancel[5010];
vector<order> buy,sell,records;

int main()
{
	string op;
	memset(cancel,0,sizeof(cancel));
	int i=1;
	double p;
	ll ans,Sumb,Sums;
	ans=Sumb=Sums=0;
	while(cin>>op){
		double a;ll b;
		if(op[0]=='b'){
			cin>>a>>b;
			records.push_back(order(i,1,a,b));
		}
		else if(op[0]=='s'){
			cin>>a>>b;
			records.push_back(order(i,2,a,b));
		}
		else{
			int no;
			cin>>no;
			cancel[no]=true;
		}
		i++;
	}
	for(int i=0;i<records.size();i++){
		if(records[i].type==1&&!cancel[records[i].idex])
			buy.push_back(records[i]);
		else if(records[i].type==2&&!cancel[records[i].idex]){
			sell.push_back(records[i]);
			Sums+=records[i].count;
		}
	}
	sort(buy.begin(),buy.end());
	sort(sell.begin(),sell.end());
	for(int i=0,j=0;i<buy.size();i++){
		Sumb+=buy[i].count;
		for(;j<sell.size()&&sell[j].price>buy[i].price;j++){
			Sums-=sell[j].count;
		}
		if(min(Sumb,Sums)>ans){
			ans=min(Sumb,Sums);
			p=buy[i].price;
		}
	}
	printf("%.2lf %lld\n",p,ans);
	return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值