大致思路
预处理输入
①开两个结构体数组rec[1000000]和tmp[5000],里面储存price(价格),buy_num(以此价格买入的数量),sell_num(以此价格卖出的数量)等信息,特别的:
rec[i]保存的是当价格为i/100时的buy_num,sell_num
tmp[i]保存的是第i行的信息
②输入时:遇到buy或者sell,就分别在rec和tmp中储存相应的信息;遇到cancel,就在rec中把对应行的信息减掉
③准备好一个数据buy_total,记录的是所有buy_num的和,cancel的时候也记得减去对应的值
开始处理
原理(DP):移动到一个合法的价格时,buy_total要减去上一个合法价格的buy_num,而sell_total要加上当前价格的sell_num。每次更新最优开盘价和最大总股数。
时间分析
由于价格可能为0~1000,所以rec数组的大小为10^6,运行时间O(10^6)。CCF老爷评测机可以过,哈哈
坑点
①本来以为可能会cancel掉cancel类型的记录,但显然是我多虑了
②当最大总股数相同时,记得取开盘价的较大值
③当处理价格时,要将输入的价格*100,此时记得用round(price*100),否则会导致精度不足的错误
④买的数量需要用long long
C++满分代码
#include <iostream>
#include <iomanip>
#include <cmath>
#include <cstring>
#define endl "\n"
using namespace std;
struct Record
{
double price;
long long buy_num, sell_num;
Record(){ price = buy_num = sell_num = 0; }
};
string op;
Record rec[1000005], tmp[5005];
int cancel, price_100, last;
long long buy_total = 0, sell_total = 0, best_price, best_total;
void input()
{
int n = 0;
while(cin>>op)
{
++n;
if(op == "buy")
{
cin>>tmp[n].price>>tmp[n].buy_num;
buy_total += tmp[n].buy_num;
price_100 = round(tmp[n].price*100);
rec[price_100].buy_num += tmp[n].buy_num;
}
else if(op == "sell")
{
cin>>tmp[n].price>>tmp[n].sell_num;
price_100 = round(tmp[n].price*100);
rec[price_100].sell_num += tmp[n].sell_num;
}
else if(op == "cancel")
{
cin>>cancel;
price_100 = round(tmp[cancel].price*100);
rec[price_100].buy_num -= tmp[cancel].buy_num;
rec[price_100].sell_num -= tmp[cancel].sell_num;
buy_total -= tmp[cancel].buy_num;
}
}
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
input();
sell_total = rec[0].sell_num;
best_total = min(sell_total, buy_total);
best_price = 0;
last = 0;
for(int i=1; i<=1000000; ++i)
{
if(!rec[i].buy_num && !rec[i].sell_num) continue;
buy_total -= rec[last].buy_num;
sell_total += rec[i].sell_num;
if(min(sell_total, buy_total) >= best_total)
{
best_total = min(sell_total, buy_total);
best_price = i;
}
last = i;
}
cout<<fixed<<setprecision(2)<<double(best_price/100.0)<<" "<<best_total;
return 0;
}