标签:第六届山东省acm竞赛 浪潮杯 stl 总结 set
题目链接:http://acm.sdut.edu.cn/sdutoj/problem.php?action=showproblem&problemid=3252
题意不难理解:每个人依次竞价投标 有三种操作 b 投标, c 撤销投标, q查询;
每次查询的结果是 Lowest Unique Price 也就是 “最小的独一无二的数”,如果没有输出 “none”;
比赛的时候我给队友讲完这道题目的题意,他们都说用线段树做,我也没多想,感觉题目不难,他们应该能做出来,接着就去翻译别的题了
但是他们在调试的时候遇到了问题。。。。
时间已经过去很久了(当时我们队很快A了三道题,结果卡在了这里),我才开始想怎么解这道题,,只是我手笨,,在纸上调试的效率太低,最后他们都没辙了,我才去敲得代码
结果很轻易的就过了样例:
【当时是这样写的】
#include <iostream> #include <map> #include <set> using namespace std; int main() { int n; cin>>n; while(n--) { int t; cin>>t; char ch;int co; set<int>se; map<int ,int >mp; for(int i=0;i<t;i++) { cin>>ch; switch(ch) { case 'b':cin>>co;se.insert(co);mp[co]++;break;//最开始用的数组储存的每个值的个数,超时, 后来换成的map,可是还是超时!! case 'c':mp[co]--;break; case 'q':int sign=0; for( set<int>::iterator it =se.begin();it!=se.end();++it)//照的lrj书上的代码敲得 //由于set中的数是递增的,所以依次遍历,直到找到,找不到输出none { if(mp[*it]==1) { cout<<*it<<endl; sign=1; break; } } if(!sign) cout<<"none"<<endl;break; } } } return 0; }连超两次时,,信心大减啊,我们都开始怀疑这个方法的正确性555, 的确,我用set 却不知道set的复杂度,而且交的太匆忙。
后来他们继续调试线段树,而我想搞清楚为啥超时,, 后来在白皮书找到了 set map的 每次插入 查找 和删除 的时间与 ”元素个数的对数“ 呈线性关系,也就是 O(nlogn)的复杂度,
我看题目数据 n有 200000 t 有 60 如果是极限情况肯定超时了(每次插入两个一样的,那个带迭代器的for循环肯定会超时,如果是O(n)的复杂度还可以一试)
这下对这种方法失望了,,
可是,眼看着队友还是没调试出结果,我又拾起了代码去想, 不一会又有了想法 要是我把投标多于一次的数 从set中删除, 然后如果 有人撤销投标,投标数又变成1,再把它插入set 这样不就不用查找了吗!? set中元素从小到大排列好的,那么第一个数,不就是结果了么,连查找都不用!!如果为空,就输出none!!
我很快把思路给队友说 ,也没管他听不听懂,,就直接去敲代码了,当时真是激动 ,还是太年轻。。
#include <iostream> #include <map> #include <set> using namespace std; int main() { int n; cin>>n; while(n--) { int t; cin>>t; char ch;int co; set<int>se; map<int ,int >mp; for(int i=0;i<t;i++) { cin>>ch; switch(ch) { case 'b':cin>>co;se.insert(co); mp[co]++;if(mp[co]>1) se.erase(co); break; //对set用的太少,erase这个函数还是在map的模板中找的 //当时还不知道对不对 case 'c':mp[co]--; if(mp[co]==1) se.insert(co);break; case 'q':int sign=0; for( set<int>::iterator it =se.begin();it!=se.end();++it)//后面的没有修改,测试样例一下就通过了 { if(mp[*it]==1) { cout<<*it<<endl; sign=1; break; } } if(!sign) cout<<"none"<<endl;break; } } } return 0; }事实证明 又一次让队友失望了,,,还是超时!!! 真是崩溃了。。 这下我们更加怀疑这个方法的正确性了。。
这时候我想起了白皮书上的 一句话, STL还是挺快的,尽管如此,对于一些时间要求非常高的题目,也会成为性能瓶颈。。
完了,想到这,这个方法就这样弃了555,, 时间剩余不多,队友继续调试树,,大家都很着急,,开始疯狂的提交。。
其实,set想到这里,离YES就剩一步之遥了,, 不,就剩下一行代码了,,可是我们却放弃了。。
出了考场,和欧神一交流,,发现他们也用的set ,而且过了,顿时血崩,再一讨论,我很快想到了自己疏忽的地方。
今天山理工挂出了省赛题,,就花了几分钟,一次AC了:
【AC代码】
#include <iostream> #include <map> #include <set> using namespace std; int main() { int n; cin>>n; while(n--) { int t; cin>>t; char ch;int co; set<int>se; map<int ,int >mp; for(int i=0;i<t;i++) { cin>>ch; switch(ch) { case 'b':cin>>co;se.insert(co);mp[co]++; if(mp[co]>1) se.erase(co);break; case 'c':cin>>co; mp[co]--; if(mp[co]==0) se.erase(co);//如果,撤销之后一次也没有了,就把他从set中删除//就是没想到这里<img alt="哭" src="http://static.blog.csdn.net/xheditor/xheditor_emot/default/cry.gif" /> if(mp[co]==1) se.insert(co);break; case 'q': if(!se.empty()) cout<<*se.begin()<<endl; else cout<<"none"<<endl;break; } } } return 0; }
说到底 还是基础太差,首先对stl性能不了解,接口也不大会用,开始超时那么多次,太影响心情,
然后就是配合,要是我把这题的思路给队友讲清楚,两个人去思考这个方法,,就一定能解出来的。
还有就是比赛心态,太着急了,交的太快,个人赛的时候还好,但是团体赛wa一次很影响士气的,所以一定要提高正确率;
FIGNTING--
山东省第六届ACM竞赛 Lowest Unique Price(set+map)分析,总结
标签:第六届山东省acm竞赛 浪潮杯 stl 总结 set
原文地址:http://blog.csdn.net/chaiwenjun000/article/details/45788907