OI 系列考试要注意什么挂点?分享自己的错误经历~

本文汇总了C++算法竞赛中常见的错误,如类型定义、空间限制、错误判断、内存操作、数据转换和编译技巧,提供了一套检查和避免错误的方法,帮助参赛者提高代码质量。
摘要由CSDN通过智能技术生成
注:本文适用于 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!!因为先加,再判断,再修改!
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 ```

//或者在程序末尾添加一个输入。

https://i-blog.csdnimg.cn/blog_migrate/87fea3400e3393954991d5fc0483ec40.png

还有一种是输出到文件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[]

  • 26
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值