注:本文适用于 C++ 算法竞赛的同学。有一些内容可能不正确,要自己验证哦!
铭记
记录自己犯过的错!
-
#define int long long
是把int
替换为long long
,不要写反 -
请注意不要暴空间! $5000\times5000$ 最大了!!
-
多组数据一定要init!!检查STL和数组,变量是否清空!!eg.【模板】栈 - 洛谷
-
不能写
!a%3
!,取反优先级大于取余!(备注:!a
当a=0或false时值为1,其余时值为0) -
size()
返回unsigned,如果size为0那么$size-1=2\times INT_{MAX}$,访问越界所以RE
-
一定要把
cerr
注释掉!不会WA但是会TLE!!! -
不要用
if(sqrt(j)*sqrt(j)==j)cout<<'!';
判定完全平方数 -
开栈!不然一下代码在跑的时候能过编,但直接死循环不让输入,原因是在进入out()函数时开的node a爆栈了。但是它不会让你跑到这个函数再re,而是一开始直接就re
string sa,sb;
struct node{
int res[N];//define为ll ,压8位
int len;
};
node init(string s){
//..
}
inline void out(node a){
cerr<<a.len<<endl;
printf("%lld",a.res[a.len]);
for(int i=a.len-1;i;i--)printf("%08lld",a.res[i]);
}
signed main(){
cin>>sa;
node a=init(sa);
out(a);
return 0;
}
-
检查空间大小的代码
bool f1;
int ans,a[N<<2];
bool f2;
signed main(){
printf("the size of your code is %lf MiB",1.00*((&f2)-(&f1))/1024/1024);
return 0;
}
-
洛谷评测机跑线段树类型题目可以跑$O(2e7)~700ms$
-
注意数组越界!尽量开大,但也不要爆空间
-
2^n可以用1<<n代替
-
交题不要交错!!
-
输出使用时间的代码
auto start = chrono::high_resolution_clock::now();
work();
auto end = chrono::high_resolution_clock::now();
cerr << "time: " << chrono::duration<double, milli>(end - start).count() << "ms" << endl;
-
检查inf(如求min时ans的初始值inf)是否够大,需不需要1e18
-
注意自己是输出!不要最末尾又多输出了一个空的ans!!删代码要删干净!!
-
模块化写代码后注意不同区域的变量/数组会不会重名!!
-
/* 吾日三省吾身: 你排序了吗? 你取模了吗? 你用%lld输出long long 了吗? 1LL<<x写对了吗? 判断=0用了abs()吗? 算组合数判了a<b吗? 线段树build()了吗? .size()加了(signed)吗? 树链剖分的DFS序是在第二次更新的吗? NTT逆变换除了项数吗? */
-
注意不要爆空间!略超空间不会导致MLE但会TLE(基本会让运行时间$\times 1.5$)
-
映射请使用
unordered_map
而不要使用map
!!时间可能会$\times 10$ -
看清楚数据大小!别把3e5写成2e5
-
并查集要记得初始化
-
多测清空不要用memset,可以用栈记录修改的位置。
-
不要memset(a,-INF,sizeof a),如果不确定请输出里面值看看!!!
-
看清楚MOD的值!!在复杂度允许下多取模(取模复杂度较大,但不卡常就不怕)
-
floating point exception的问题原因:可能是除0或者%0
-
!!如果怕取模出问题,那么就在输出时把(ans%MOD+MOD)%MOD(推荐)
-
注意不同的数组开的空间不一样!比如存边的和存点的数组大小就不一样。
-
考场上第一件事把编译器的O2打开!!!不然有一些时候RE检查不出来!!!
-
注意for是先加再检查。看看下面的代码是什么问题?
for(int i=1;i<=40&&x[i]<=INF&&y[i]<=INF;i++){
x[i]=2*x[i-1]+bx,y[i]=2*y[i-1]+by;cnt++;
}
//答案:x[i],y[i]一直是0!!因为先加,再判断,再修改!
-
注意枚举模拟时还原初始状态!!!
-
如果发现看错了题目,那么一定要在改代码时不要漏掉没改
-
不要懒!有时间就测大样例!有多少测多少
-
编译防数组越界和整型越界:编译选项关于GCC/LLVM编译器中的sanitize选项用处用法详解 - 知乎
-
注意结构体重载运算符
struct node{
int w;
bool operator < (const node &b) const{//如果是b[1]<b[2],相当于调用了b[1]的<,把b[2]作为参数传入。那么括号内的就是b[2],括号外的就是b[1]
return w < b.w;
}
}b[N];
main(){
b[1].w=1;b[2].w=2;
if(b[1]<b[2])cout<<"OK";
else cout<<"NO";
}
//output: OK
-
判 UB:
-fsanitize=address,leak,undefined,signed-integer-overflow
! -
别memset INF!!一定会WA!!除非用0x3f
-
写另外的题目时记得修改模数!别忘了!
-
注意即时访问map空节点也会产生新内存占用!因此即使map为空,从1到inf扫一边还是会MLE。解决方法:访问后如果是0,~~则先
erase
清空,然后不时shink_to_fit
压缩内存~~ 无此函数! -
不能根据度数为1来确定叶子节点!!度数为1不代表叶子节点!!
-
注意对double数组memset不能为INF=0x3f!而应该是0x7f。万金油就是输出看看!!
-
注意double×double可能会冒出科学计数法!要整体强制转换为int才行,错误写法
(int)ceil(1.00*n/a)*ceil(1.00*m/a)
,正确写法(int)(ceil(1.00*n/a)*ceil(1.00*m/a))
-
多测记得清空,特别是vector存图时要清空vector,会MLE,WA
-
不要把快读和同步流cin一起用!会WA!
-
注意不要对double使用快读!!
-
注意玄学!
-
注意节点开始的编号!
-
一种奇怪的MLE方法:dfs死循环导致爆栈MLE
-
再次提醒别除0!检查每一个除法是否有除0的可能。每一次写代码都要检查特别是打比赛!
-
在进行数组复用时,注意这个数组当前是否被占用了!(练习 | 这人怎么天天刷题啊'城市环路)
-
注意,虽然会忽略行末空格和文件末尾换行,但是中间的换行不会忽略!别多输出了!会WA
未验证的铭记
把看见的别人犯过的错都记录下来!!
- 字符型数组数不可以通过memset函数清0的, 因为即使只是把内存清空,也会引起翻车
交题前必查
-
再次提醒别除0!检查每一个除法是否有除0的可能。每一次写代码都要检查特别是打比赛!
-
INF范围,没有加法就开大
-
数组大小,不要小了或者大了。重点检查会不会小了!
-
检查返回值与函数类型的关系。
考前口诀
二分有等有加减。ans取mid在l更。
空间不大也别小,fre open别写错。
测试用建议编译命令:
g++ -Wall -O2 -std=c++14 -fsanitize=address,leak,undefined,signed-integer-overflow -o "%e" "%f"
编译命令
-static
此选项将禁止使用动态库,所以,编译出来的东西,一般都很大,也不需要什么动态连接库,就可以运行。
-fsanitize=address,leak,undefined,signed-integer-overflow
必备的好吧,但是会和static冲突,所以不能一起用。最后测试时记得先用-fsanitize检查,后用-static测试。
‐O2 ‐std=c++14 ‐static
测试标准命令
Windows编译常见问题
-
数组开太大会导致在线ide发生RE错误
-
如果在进入main()之前就发生了死循环,请考察是否爆栈
DevC++中
工具→编译选项,在编译时加入以下指令处打上勾,同时加入以下代码
-Wl,-stack=134217728
运算符优先级
优先级值越大,表示优先级越高。
define用法
建议初期写第一种
//第一种写法,建议用于写函数,必须写成函数类型
#define add(x,y) (x+y)
#define rp(1,a,b) for(int i=1;i<=(a),i+=(b))
//第2种写法,"#n"可以将n转换为字符串嵌入
#define PXN(n) printf(" x"#n" \n")
//第3,##n可以将n与前面的部分联合起来
#define PXN(n) printf("%d\n",b##n)
注意,以下写法不可取
#define PXN(n) printf("##n\n",b2)//期望PXN(abc)>>输出字符串abc
#define PXN(n) printf("%d \n",b"#n")//期望PXN(2)>>输出b2的值
关于printf
规定符
-
%d 十进制有符号整数
-
%u 十进制无符号整数
-
%f 浮点数
-
%s 字符串
-
%c 单个字符
-
%p 指针的值
-
%e 指数形式的浮点数
-
%x, %X 无符号以十六进制表示的整数
-
%o 无符号以八进制表示的整数
-
%g 把输出的值按照 %e 或者 %f 类型中输出长度较小的方式输出
-
%p 输出地址符
-
%lu 32位无符号整数
-
%llu 64位无符号整数
-
%% 输出百分号字符本身。
除了格式化说明符之外,printf() 函数还支持一些标志和选项,用于控制输出的精度、宽度、填充字符和对齐方式等。例如:
-
%-10s:左对齐并占用宽度为 10 的字符串;
-
%5.2f:右对齐并占用宽度为 5,保留两位小数的浮点数;
-
%#x:输出带有 0x 前缀的十六进制数。
编译技巧
没有Dev-c++,仅有 Sublime怎么编译运行?
方法1:再找一遍Dev-c++
方法2:使用命令行进行编译
编辑一个 run.bat
内容如下
t g++ a.cpp -o out.exe out.exe
其中`a.cpp`为源文件名称
然后就可以在命令行里输入啦
那么怎么样查看输出呢?
很简单,一种是在代码里加入暂停的代码(具体的自行百度)
C++ system("pause");//仅限Windows ```
//或者在程序末尾添加一个输入。
还有一种是输出到文件 用freopen
即可
字符串与数字转换
小技巧
- 字符串转数字
可使用atof(char *str)
把字符串转换为一个double类型的浮点数。atof()
定义在math.h中。
对于string则应该使用stof()
- string转int
用stoi,stol,stoll
,注意如下:
std::stoi("45") is 45 std::stoi("3.14159") is 3 std::stoi("31337 with words") is 31337
- 数字转字符串
to_string(int/double/LL)
返回值为string类型。
头文件:#include
- 多类型转字符串
sprintf()
函数 1、该函数包含在stdio.h的头文件中。 2、sprintf和平时我们常用的printf函数的功能很相似。sprintf函数打印到字符串中(要注意字符串的长度要足够容纳打印的内容,否则会出现内存溢出),而printf函数打印输出到屏幕上。sprintf函数在我们完成其他数据类型转换成字符串类型的操作中应用广泛。
样例:sprintf(tmp,"%d%d",i,j);
tmp为char[]