题目
问题描述
某股票交易所请你编写一个程序,根据开盘前客户提交的订单来确定某特定股票的开盘价和开盘成交量。
该程序的输入由很多行构成,每一行为一条记录,记录可能有以下几种:
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<iomanip>
#include<string>
#include<cstring>
#include<cstdlib>
using namespace std;
double a[5002][2][2];//二维数组,第二位分别代表buy,sell
void deal(string str,int n)
{
if(str==" ")
return;
string comm;
int index=str.find(" ");
double data;
comm=str.substr(0,index);
if(comm=="cancel")
{
comm=str.substr(index+1,str.find(" ",index+1)-index-1);
int line=atoi(comm.c_str());
a[line][0][0]=0;
a[line][0][1]=0;
a[line][1][0]=0;
a[line][1][1]=0;
return;
}
if(comm=="buy")
{
comm=str.substr(index+1,str.find(" ",index+1)-index-1);
data=atof(comm.c_str());
a[n][0][0]=data;
index=str.find(" ",index+1);
comm=str.substr(index+1,str.find(" ",index+1)-index-1);
data=atof(comm.c_str());
a[n][0][1]=data;
return;
}
if(comm=="sell")
{
comm=str.substr(index+1,str.find(" ",index+1)-index-1);
data=atof(comm.c_str());
a[n][1][0]=data;
index=str.find(" ",index+1);
comm=str.substr(index+1,str.find(" ",index+1)-index-1);
data=atof(comm.c_str());
a[n][1][1]=data;
return;
}
}
void open(int n)
{
int i,j,k;
double max=0,now;
long long maxi=0,mis,mib,mi;
for(i=1;i<n;i++)
for(j=0;j<2;j++)
{
if(a[i][j][0]!=0)
{
now=a[i][j][0];
mis=0;
mib=0;
for(k=0;k<n;k++)
{
if(a[k][0][0]==0&&a[k][1][0]==0)
continue;
if(a[k][0][0]>=now)
mib+=a[k][0][1];
if(a[k][1][0]<=now)
mis+=a[k][1][1];
}
if(mis>mib)
mi=mib;
else
mi=mis;
if(mi>maxi)
{
max=now;
maxi=mi;
}
if(mi==maxi&&now>max)
{
max=now;
maxi=mi;
}
}
}
cout<<fixed<<setprecision(2)<<max;
cout<<" "<<maxi;
}
int main(int argc, char *argv[]) {
memset(a,0,sizeof(a));
int n=1;
string str;
getline(cin,str);
str+=" ";
deal(str,n++);
while(str!=" ")
{
getline(cin,str);
str+=" ";
deal(str,n++);
}
open(n);
return 0;
}
我的思路
实时录入一行行的数据,我申请了一个三维数组,第二维下标为0代表buy,第二维下标为1代表sell,第三位分别代表出价,股数,如果是cancel,初始化(清空)相应行数据,但是保证cancel独占一行,但是本行没有实际含义数据
至于计算开盘价没有什么难度
本题有一些需要注意的地方
- 我录入数据的时候是以再回车一次结束,这里是getline,所以本身不会存储回车数据,我是判断getline读取为空串(我这里再加一个空格所以是包含一个空格的串),这时读取结束
- 由于提到股数超10^8所以,开盘成交量可能超过int,所以最好把成交量用long long存储
- 题目中提到如果求得的开盘成交量相同,则取开盘价大的那一个作为结果
- 本题我遇到问题后,发现其他博客涉及到cancel的问题,但是我的代码是实时录入数据而且没有用到自定义类无意中没有涉及到cancel的问题,但是cancel这方面的问题也稍微说一下:
- 只需要记住,对同一行指令使用多次cancel不会产生起死回生的作用,相应行数据只要有cancel作用就无效
- 题目没有涉及到对cancel cancel的案例,不要多考虑