这题初看题意还是比较友好的,相比于前面几题来说,思路并不是很难想。但是,题目描述误导我了很久,以至于我debug了很久,再次强调英语阅读理解的重要性(认真脸)。不过接下来就是无尽的TLE...
尝试了很多方法,但都没什么用,后来无奈只能查了网上的解法,发现最终的quote都是提前存好的,不是像我要算的时候再计算出来,而且每一个请求都是按照id存储起来以便cancel修改状态。如果用我原来的方法,只使用两个优先队列和一个cancel的数组,每次的quote只能自顶向下遍历还得找是否在cancel里面。最致命的是,优先队列只支持一次访问顶层元素,因此每次访问完需要pop掉顶层元素。然而这步操作是非法的,因此只能copy过来进行这些操作。数据多的时候,这个copy操作的代价可想而知。。
其实这也说明了优先队列(其实就是堆)的一大弱点,只能合法地访问顶层元素,因此如果还想同时访问其他的元素而不改变原有的数据结构,最好是换一种数据结构或是再构造其他的数据结构,比如说这题,把其他请求用一个数组存储,再把答案存在price与size映射的map里面来达到只访问顶层元素就可以获得答案的效果,是一种用空间换时间的方法。只不过自己太笨没有想到。
另外还学到一点,就是用模板代替类型优化代码量,不过我这代码简直就是***,无从优化。可以同时定义<和>操作符,用greater调用大于操作符。
另外还发现了一点,就是优先队列被pop掉最后一个元素时,这个元素并不会真正被删除,依然存在队列的最顶层(可以用top函数输出),不知道是不是人为设计的。总之不能用top元素作为判断依据,因为当它是最后一个元素时是删不去的,最好前面加一个是否为空的判断。
极其辣眼睛的代码:
#include <iostream> #include <cstring> #include <cstdio> #include <queue> #include <algorithm> #include <ctime> #include <map> #include <bitset> #define _for(i, a, b) for (int i = (a); i < b; ++i) #define _rep(i, a, b) for (int i = (a); i <= b; ++i) //#define fre //#define DEBUG using namespace std; struct Reqbuy { int id, p, s; Reqbuy(int id, int p, int s): id(id), p(p), s(s) {} bool operator < (const Reqbuy& b) const { if (p == b.p) return id > b.id; else return p < b.p; } }; struct Reqsell { Reqsell(int id, int p, int s): id(id), p(p), s(s) {} int id, p, s; bool operator < (const Reqsell& b) const { if (p == b.p) return id > b.id; else return p > b.p; } }; struct Req { int p, s = 0, type; } req[10005]; map<int, int> buytots, selltots; //这一步太妙了 bitset<10005> bit; int quote[4] = {0, 0, 0, 99999}; void updatequo(priority_queue<Reqbuy>& buyorder, priority_queue<Reqsell>& sellorder) { while (!buyorder.empty() && ~bit[buyorder.top().id]) buyorder.pop(); //最后一个top删不去 while (!sellorder.empty() && ~bit[sellorder.top().id]) sellorder.pop(); if (buyorder.empty()) quote[0] = 0, quote[1] = 0; else { quote[0] = buytots[buyorder.top().p]; quote[1] = buyorder.top().p; } if (sellorder.empty()) quote[2] = 0, quote[3] = 99999; else { quote[2] = selltots[sellorder.top().p]; quote[3] = sellorder.top().p; } printf("QUOTE %d %d - %d %d\n", quote[0], quote[1], quote[2], quote[3]); } void buy(int p, int s, int id, priority_queue<Reqbuy>& buyorder, priority_queue<Reqsell>& sellorder) { int trades, tradep; while (!sellorder.empty() && s > 0 && sellorder.top().p <= p) { if (~bit[sellorder.top().id]) { sellorder.pop(); continue; } tradep = sellorder.top().p; if (sellorder.top().s <= s) { trades = sellorder.top().s; s -= sellorder.top().s; req[sellorder.top().id].s -= trades; selltots[sellorder.top().p] -= trades; sellorder.pop(); } else { trades = s; req[sellorder.top().id].s -= trades; selltots[sellorder.top().p] -= trades; Reqsell tmp = sellorder.top(); tmp.s -= s; sellorder.pop(); sellorder.push(tmp); s = 0; } printf("TRADE %d %d\n", trades, tradep); } if (s > 0) { req[id].p = p, req[id].s = s, req[id].type = 0; if (!buytots.count(p)) buytots[p] = s; else buytots[p] += s; buyorder.push(Reqbuy(id, p, s)); } updatequo(buyorder, sellorder); } void sell(int p, int s, int id, priority_queue<Reqbuy>& buyorder, priority_queue<Reqsell>& sellorder) { int trades, tradep; while (!buyorder.empty() && s > 0 && buyorder.top().p >= p) { if (~bit[buyorder.top().id]) { buyorder.pop(); continue; } tradep = buyorder.top().p; if (buyorder.top().s <= s) { trades = buyorder.top().s; s -= buyorder.top().s; req[buyorder.top().id].s -= trades; buytots[buyorder.top().p] -= trades; buyorder.pop(); } else { trades = s; Reqbuy tmp = buyorder.top(); tmp.s -= s; req[buyorder.top().id].s -= trades; buytots[buyorder.top().p] -= trades; buyorder.pop(); buyorder.push(tmp); s = 0; } printf("TRADE %d %d\n", trades, tradep); } if (s > 0) { req[id].p = p, req[id].s = s, req[id].type = 1; if (!selltots.count(p)) selltots[p] = s; else selltots[p] += s; sellorder.push(Reqsell(id, p, s)); } updatequo(buyorder, sellorder); } int main() { #ifdef fre freopen("in.in", "r", stdin); freopen("out.txt", "w", stdout); #endif int n; char line[100]; int a, b; bool fir = true; while (~scanf("%d", &n)) { if (fir) fir = false; else putchar('\n'); priority_queue<Reqbuy> buyorder; priority_queue<Reqsell> sellorder; gets(line); bit.set(); buytots.clear(); selltots.clear(); memset(req, 0, sizeof(req)); _rep(i, 1, n) { gets(line); /*#ifdef DEBUG printf("%s", line); cout << endl; #endif*/ if (line[0] == 'C') { a = 0; for (int i = 7; line[i]; ++i) a = (a << 3) + (a << 1) + line[i] - 48; bit[a] = 0; if (req[a].s != 0) { if (req[a].type == 0) buytots[req[a].p] -= req[a].s; else selltots[req[a].p] -= req[a].s; req[a].s = 0; } updatequo(buyorder, sellorder); } else { a = 0, b = 0; int ti; if (line[0] == 'B') { //用sscanf跟这个时间复杂度相当 for (ti = 4; line[ti] != ' '; ++ti) a = (a << 3) + (a << 1) + line[ti] - 48; for (++ti; line[ti]; ++ti) b = (b << 3) + (b << 1) + line[ti] - 48; buy(b, a, i, buyorder, sellorder); } else { for (ti = 5; line[ti] != ' '; ++ti) a = (a << 3) + (a << 1) + line[ti] - 48; for (++ti; line[ti]; ++ti) b = (b << 3) + (b << 1) + line[ti] - 48; sell(b, a, i, buyorder, sellorder); } } } } #ifdef DEBUG printf("time used %.2f", double(clock()) / CLOCKS_PER_SEC); //输出时间 #endif }