做题须知与禁忌

1. 多测(多组数据评测)

  • 注意看题!请注意本题是不是多测。而且通常题目中只有一句话,有时又藏得隐蔽,一定要细心看!
  • 数据较多时,多测避免用 vector 以及基于 vector 的容器。因为多测一般要清空,而 vector 清空不会释放内存,这就导致内存爆炸。
  • 注意清空!但是更要注意内存。 memset 函数效率很高,但是用了它没有调用过的内存就会被快速覆盖上给定的字节。于是乎不论数据多小内存都是占满了的。也许本来有部分分,现在全部爆了。

2. STL

  • 关于 c++ STL deque,list,queue 与 stack
  • STL 容器迭代器坑
  • std::multiset::erase(type val) 当指定元素的值的时候,删除所有为这个值的元素。因此若只想删除其中一个,应使用:std::multiset::erase(std::multiset::find(type val))
  • 有时候用闭区间(即:\([1,n]\))时,unique 记得减一。比如:int nend=unique(a+1,a+1+n)-a-1

3. 数据范围

  • 通常来讲,\(20\) 以内复杂度是 \(O(2^n)\) 如状压;\(120\) 以内是 \(O(n^4)\) 但常数得足够小,比如 \(0.5\)\(300\) 以内是 \(O(n^3)\)\(2000\) 以内 \(O(n^2\log n)\)\(10000\) 以内 \(O(n^2)\)\(7\times 10^5\) 以内 \(O(n\log n)\)\(10^7\) 以内线性。通常不会有 \(O(\log n)\) 的题。
  • 但是应注意出题人有时会故意把范围缩小让你摸不透算法,结果做出一个超麻烦的方法。比如一道 \(O(n)\) 的题数据范围却是 \(10^5\)。(也有可能是常数因子比较大。)
  • std::sort 一定要注意,定义仿函数或重载小于符号时 \(a<b\)\(b<a\) 不能同时为真,即最终返回不出现等号。否则数据范围一大就 CE。

4. 标准库与拓展库

  • 当应用到两个及以上命名空间的时候,避免使用 using namespace std,其余名字空间不可暴露在全局中(即不声明)。使用 :: 来访问,比如 __gnu_pbds::priority_queue<int> Q

  • 用拓展库的时候,不要使用标头 <bits/extc++.h>,会报错,原因和解决办法见这里。少使用 <bits/stdc++.h>,不好用!原因是它不是 Dev 的浅层文件,写代码的时候找不到,只有编译的时候找得到。

5. 平台特性

  • UVa 多测不能用 while(scanf("%d",&n)!=EOF) 或者 while(~scanf("%d",&n)),会超时。只能用 while(cin>>n)。实际上,Uva 的 scanf 好像就有问题/kk。
  • POJ 作为同样老的 OJ (也被称作“破 OJ”),不使用 -static 编译指令。

6. 头文件

  • <iostream> 在标准中没有规定要包含 <cstdio>。为了保险,请在声明头文件的时候把两个都带上。
  • <vector> <cmath> 这两个头文件内的一些函数和类在 DevC++ 中不需要声明可以过编译。但是一定要把它们俩带上,因为似乎除了 DevC++ 的其他编译器都过不了。

7. OI 赛场编译(转载自 LOJ 如何在不提供 NOIlinux 2.0 环境的考点避免编译错误

  • #include<bits/stdc++.h>(内含 OI 通常能用到的所有头文件)而不是逐个写头文件,以免实际上漏了头文件但本地环境自动补齐。
  • 把整个程序装进自己的 namespace,以免和库中的名称冲突(比如 nextpipe
  • 如果题目没有特别说明,编译选项尽量加上 -std=c++14。如果这样不能编译(指的是编译器版本过低不支持 C++14 而不是你的程序编译错误!),就至少加上 -std=c++11
  • 编译选项加上 ``-Wall`,让编译器提醒一些常见错误,比如函数不写返回值。
  • 编译选项加上 -fno-ms-extensions(关闭一些和 msvc 保持一致的特性,例如,关闭后不标返回值类型的函数会报 CE 而不是默认为 int)。

示例程序:

#include<bits/stdc++.h>

using namespace std;

namespace my_namespace{
    int main(){
        int a,b;
        cin>>a>>b;
        cout<<a+b<<endl;
        return 0;
    }
};

int main(){
    return my_namespace::main();
}

编译选项:

g++ a.cpp -o a -std=c++14 -O2 -Wall -fno-ms-extensions

8. 内存使用问题

通常我们申请新空间使用 new 而清理内存使用 delete。(还有一种使用类的方法,但我不记得了……)

但是!有时候 new 会增加不必要的程序占用空间,而据说这是内存碎片造成的。

当你的程序中 delete 可能用不到或者很少用的时候,也许开一个内存池更好(能够防止炸空间)。

比如:

class Node {
	Node() {}
}; 

Node *nodes;

Node* newNode() {return new Node();}

可以替换成:

class Node {
	Node() {}
}; 

const int MAXSIZE=1e6+6;
Node nodePool[MAXSIZE];
Node *poolPointer=nodePool;

Node* newNode() {return poolPointer++;}

这样就避免炸空间了。

posted @ 2022-12-06 17:22  robinyqc  阅读(156)  评论(0编辑  收藏  举报