CCF 201412-3 集合竞价 90分代码 C++

本文介绍了一种程序设计问题,目标是确定股票开盘价以最大化成交量。程序需要处理买入、卖出和取消订单的记录,并在不同条件下匹配买卖单。通过排序和遍历策略找出最大成交量的开盘价。90分代码与100分代码的主要区别在于优化了数据处理和开盘价选择的过程。

问题描述
  某股票交易所请你编写一个程序,根据开盘前客户提交的订单来确定某特定股票的开盘价和开盘成交量。
  该程序的输入由很多行构成,每一行为一条记录,记录可能有以下几种:
  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。
90分代码:
思路:买价大于等于售价才能成交,题目就是求个最佳的阈值,使得成交量最高。
先把所有数据存在一个大数组中,去掉cancel的行之后,在把数据分到buy和sell数组。求最大成交量的时候,分别根据价格进行排序,从buy中选最好的开盘价(因为成交量相同的情况下要求选开盘价高的),buy从后往前遍历,记录大于某个价格的买者股数,同时在sell中从前往后记录售价小于买价的总售卖股数,实际的成交量为两者中较小的,依次循环,找到使得成交量最大的价格,即定为开盘价。
明明跟那个100分代码快一模一样了,还是90,硬生生看了几个小时后,暂时放弃……太打击人了……第三题注定是无法完整的……

#include <iostream>
#include <algorithm>
#include <string>
#include <iomanip> 
using namespace std;//用string之前一定要声明名称空间 
struct record{
	string str;
	double price;
	long long num;
}; 
bool cmp(record r1,record r2)
{
	return r1.price<r2.price;
}
int main()
{
	record buy[5001],sell[5001],total[5001];
	int num[5001]={0};
	record temp;
	int del;
	double ans_price=0;
	long long ans_num=0;
	int n=1;
	
	//因为有需要删除的行,所以先把所有的行先接收到  
	//一个大数组中,便于以后分类和去除被删除行 
	while(cin >> total[n].str)
	{
		if(total[n].str=="buy"||total[n].str=="sell")
		{
			cin >> total[n].price >> total[n].num;	
		}
		else if(total[n].str=="cancel")
		{
			cin >> del;
			num[del]=1;
		}	
		n++;
	}
	//分类到buy和sell 
	int m=0,k=0;
	for(int s=1;s<n;s++)
	{
		if(num[s]==0)
		{
			if(total[s].str=="buy")  buy[m++]=total[s];
		    else sell[k++]=total[s];
		}
	}
	sort(buy,buy+m,cmp);
	sort(sell,sell+k,cmp);
	//遍历,比较得出使得开盘成交量尽可能地大的开盘价
	//系统可以将所有出价至少为p0的买单和所有出价至多为p0的卖单进行匹配。
    //开盘成交量为出价至少为p0的买单的总股数和所有出价至多为p0的卖单的总股数之间的较小值。 
    long long numb=0,nums=0,min_num=0;
	for(int i=m-1;i>=0;i--)
	{
		numb+=buy[i].num;//累加,大于等于当前buy[i].price的股票数 
		nums=0;//注意每一轮要置成0 
		for(int j=0;j<k;j++)
		{
			if(buy[i].price<sell[j].price)
			     break;
			nums+=sell[j].num;
		}
		if(numb<nums) min_num=numb;
		else min_num=nums;//开盘成交量为两者中较小值 
		if(min_num>ans_num)//使得开盘成交量最大的开盘价 
		{
			ans_num=min_num;
			ans_price=buy[i].price;			
		}
	} 
	cout << setiosflags(ios::fixed) << setprecision(2) << ans_price << " ";
	cout << ans_num << endl;	 
	cout<<endl;
	return 0;
} 

100代码:

/*201412-3集合竞价
问题描述
  某股票交易所请你编写一个程序,根据开盘前客户提交的订单来确定某特定股票的开盘价和开盘成交量。
  该程序的输入由很多行构成,每一行为一条记录,记录可能有以下几种:
  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。
*/
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
using namespace std;
struct Record
{
	string a;
	double p;
	long long s;
};
Record buy[5001],sell[5001],record[5001];
int num[5001]= {0};
int b=0,s=0;
long long numb=0,nums=0;
long long mm;
long long mins=0;
double minp=0;
int main()
{
	int n=1;
	while(cin>>record[n].a)
	{
		if(record[n].a!="cancel")
		{
			cin>>record[n].p>>record[n].s;
			n++;
		}
		else
		{
			int del;
			cin>>del;
			num[del]=1;
			n++;
		}
	}
	for(int i=1; i<n; i++)
	{
		if(num[i]==0)
		{
			if(record[i].a=="buy")
			{

				buy[b].a="buy";
				buy[b].p=record[i].p;
				buy[b].s=record[i].s;
				b++;
			}
			else
			{
				sell[s].a="sell";
				sell[s].p=record[i].p;
				sell[s].s=record[i].s;
				s++;
			}
		}
	}
	for(int i=0; i<b; i++)
	{
		for(int j=i+1; j<b; j++)
		{
			if(buy[i].p>buy[j].p)
			{
				swap(buy[i].p,buy[j].p);
				swap(buy[i].s,buy[j].s);
			}
		}
	}
	for(int i=0; i<s; i++)
	{
		for(int j=i+1; j<s; j++)
		{
			if(sell[i].p>sell[j].p)
			{
				swap(sell[i].p,sell[j].p);
				swap(sell[i].s,sell[j].s);
			}
		}
	}
	for(int i=b-1; i>=0; i--)
	{
		numb+=buy[i].s;
		nums=0;
		for(int j=0; j<s; j++)
		{
			if(buy[i].p<sell[j].p)
				break;
			nums+=sell[j].s;
		}
		mm=min(numb,nums);
		if(mm>mins)
		{
			mins=mm;
			minp=buy[i].p;
		}
	}
	printf("%.2lf %lld",minp,mins);
	cout<<endl;
	return 0;
}
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值