山东省第六届ACM竞赛 Lowest Unique Price(set+map)分析,总结

题目链接: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--

posted @ 2015-05-17 15:05  编程菌  阅读(190)  评论(0编辑  收藏  举报