写代码易错点整理ll与int变量重复声明c 未初始化int 的神奇现象结构体相关引用swap使用栈堆的 top元素引用vectorresizepush_back更好用动态规划dfs回溯型DP背包set操作不能一边遍历一边删除元素和插入元素rbegin()的迭代器vector指针的使用位运算思维易错题整理动态规划容易读错题的题意理解字符串ll与int造成二分查找无法退出当r,l为ll类型而mid声明为int类型变量重复声明会导致越界错误结果错误等。调试时会发现某个值突然很大有可能是重复声明导致的。n,m这些变量不要声明为全局变量每个函数里自定义这点时间复杂度不影响。c 未初始化int 的神奇现象voidpushup(intk){inta,b;// a 0;// b 0;aabs(a);babs(b);couta bendl;intc__gcd(a,b);couta b cendl;if(tree[k].left_son!-1){atree[tree[k].left_son].sum;}if(tree[k].right_son!-1){btree[tree[k].right_son].sum;}//couta bendl;tree[k].sumfunc(a,b);}打印结果为 -364792988 1-196826616 1 1a的前后值在gcd之前前后不相同因为a,b本身并不是一个变量他只是指向栈上一片内存如果后续直接修改a,b的值甚至会影响栈上其他变量的大小如kk的值如果很大会导致数组越界访问未初始化的局部变量有可能会修改其他正常变量这取决于具体的情况。在C/C中局部变量存储在栈上栈内存不会自动清零局部变量未初始化时其值是不确定的可能是之前使用过的内存中的数据。若未初始化的局部变量的操作涉及到内存越界或者覆盖其他变量所在的内存区域就可能修改其他正常变量的值。例如当使用未初始化的指针变量时如果对其进行解引用操作指针可能指向任意内存区域若该区域恰好是其他正常变量的内存位置就会修改其他正常变量的值这会导致程序运行不稳定行为不可预测甚至可能产生灾难性后果。下面是一个简单的C语言示例展示未初始化的局部变量可能带来的问题#includestdio.hintmain(){inta10;intb;// 未初始化的局部变量int*ptr;ptrb;*ptr20;// 对未初始化的局部变量赋值// 可能会因为栈内存布局问题b的内存位置覆盖了a的位置printf(a的值: %d\n,a);return0;}在这个示例中未初始化的局部变量b被赋值后由于栈内存的布局情况可能会影响到其他正常变量的值。结构体相关当结构体和哈希表一起使用时必须添加一个缺省参数的构造函数示例题目structnode{intuid,tid,p;node(){}//这个必须有node(inta,intb,intc){uida;tidb;pc;}booloperator(constnodea)const{if(pa.p){returntida.tid;}returnpa.p;}};unordered_mapint,nodeinfo;intkey0;info[key]node(1,2,3);//这里如果没有缺省参数的构造函数会报错引用swap使用比如一个函数中boolfunc(vectorvectorintpresum1,vectorvectorintpresum2{swap(presum1,presum2);}这样的使用会导致presum1和presum2中下一次调用时的真正指向的数组已经swap如果换成指针就可以避免下次调用时还是原来的。为了在使用引用时也可以swap,可以加一个bool变量进入这个函数时看一下是否被swap过。boolflagfalse;boolfunc(vectorvectorintpresum1,vectorvectorintpresum2,inta,intb,intc,intd,intn){if(flag){swap(presum1,presum2);flagfalse;}//万一要执行swap操作就将flag置为true}栈堆的 top元素引用注意栈顶堆顶元素的引用应该在pop操作之前使用如果在pop()之后对 堆顶栈顶元素进行操作实际上获取的是pop之后新产生的栈顶和堆顶。下面两种写法的结果得到的x,y值相同priority_queuepairint,int,vectorpairint,int,decltype(cmp)pq(cmp);while(!pq.empty()){pq.pop();autotmppq.top();intxtmp.first,ytmp.second;}priority_queuepairint,int,vectorpairint,int,decltype(cmp)pq(cmp);while(!pq.empty()){autotmppq.top();pq.pop();intxtmp.first,ytmp.second;}vectorresizedist.resize(n,inf);//错误用法只有超出原本大小的元素会被置为inf,并不是每次执行会将所有元素置为infpush_back更好用vector中不支持二维向量使用emplace_back({2,4});这样的操作而push_back是可以的所以我们就只用push_back。动态规划题目传送门解法树上背包dfs回溯型DPdfs回溯型DP时时除了dp数组可以共用其他的数组都不能共用错误示例如下intprofit_0[165]{0};intprofit_1[165]{0};intdfs(intid,intb,inthalf,intfa,vectorvectorintadj,vectorintp,vectorintf){if(b0)return0;if(dp[id][b][half]!-1){returndp[id][b][half];}intret0;intpricehalf1?(p[id-1]/2):p[id-1];//首先计算本尊购买intans0;if(bprice){ansf[id-1]-price;intleft_bb-price;if(left_b0){//这里直接重置为0将导致在计算dfs时共用了同一个数组数据错误memset(profit_0,0,sizeof(int)*left_b);memset(profit_1,0,sizeof(int)*left_b);for(autonext:adj[id]){if(nextid)continue;for(intj1;jleft_b;j){for(intk0;kj;k){intson_getdfs(next,k,1,id,adj,p,f);inthaveson_getprofit_0[j-k];profit_1[j]max(profit_1[j],have);}}swap(profit_1,profit_0);}ansprofit_0[left_b];}}retmax(ret,ans);//计算本尊不买......dp[id][b][half]ret;returnret;}背包优化空间时的第二层容量的循环必须从大到小遍历而不是从小到大遍历背包DP一次性把所有的算出来不要算一半下一次进来再算一半这样算的结果是错的因为背包DP的语义已经发生了变化。比方说只算算了只有十块钱的答案现在要算12块钱的答案在处理第一个商品时如果它的价值为2此时不应该用到之前处理过的十块钱答案错误示例如下intback_0[165][2][165]{0};intback_1[165][2][165]{0};intlen[165][2]{0};//记录上一次计算了到了多少预算intdfs(intid,intb,inthalf){inthas_lenlen[id][half];if(len[id][half]b){returnback[id][half][b];}for(autonext:adj[id]){for(intjhas_len;j160;j){for(intk0;kj;k){intson_getdfs(next,k,half,id,adj,p,f);inthaveson_getback_0[id][half][j-k];//此时获取到的back_0是有问题的不符合背包语义之前已经算的结果包含了第0个儿子back_1[id][half][j]max(back_1[id][half][j],have);}}//测试下只交换指针for(intjhas_len;j160;j){swap(back_1[id][half][j],back_0[id][half][j]);}}returnback_0[id][half][target_b];}set操作不能一边遍历一边删除元素和插入元素这倒不是因为会发生迭代器失效的情况主要是——在遍历过程中删除元素有可能会删除尚未遍历到的元素导致我们遍历的结果会漏掉一些本应该遍历到的元素。删除元素只会导致该位置的迭代器失效其他元素的迭代器依然有效元素在内存中的位置不变迭代器只是会修改元素之前的相互指针。tips: 已删除迭代器取值*会触发coredump因为对应空间已经被释放然而it是可以操作的即对一个已经erase的迭代器执行操作允许。在遍历过程中插入元素有可能导致后续遍历到刚插入的元素遍历个数增加。2对于set来说自带去重功能自定义比较函数后如果比较函数中的值相同虽然插入的元素不同比较的值相同也只会插入一个元素不会将两个不同的元素都插入。rbegin()的迭代器1不能对其调用erase函数2如果此时已经获取到到了最后一个iterator希望获取到倒数第二个元素使用it,自动是逆序前进的。不能使用iter–。逆序的iter,执行的就是逆序参考例题中的使用vector不能一边删除一边遍历因为删除时该位置后面的迭代器都会失效后续元素的位置会发生变化导致下一步遍历的元素不是我们希望遍历的位置参考视频指针的使用题目传送门for(inti1;in;i2){intli;intrn-1-l;vectorTreeNode*leftallPossibleFBT(l);vectorTreeNode*rightallPossibleFBT(r);//注释了的是错误的方法for(intj0;jleft.size();j){//root-left left[j];for(intk0;kright.size();k){//root-right right[k];ret.emplace_back(newTreeNode(0,left[j],right[k]));//root new TreeNode(0);}}}位运算正确写法判断某一位是否为1如果为1则... if(ij 1){ }错误写法结果正确但是逻辑上不正确判断某一位是否为1如果为1则... if(ij 1 0){ }优先级顺序为 右移运算 比较符 按位与那么实际上执行的是((ij) (10)),操作结果还是 ((ij)1))结果与正确写法相同思维易错题整理https://mirror.codeforces.com/contest/1974/problem/D动态规划考虑操作类型时考虑不操作的情况不能漏掉典型题目容易读错题的题意理解字符串1字符串 s 分割成 k 个等长的子字符串然后重新排列这些子字符串并以任意顺序连接它们使得最终得到的新字符串与给定的字符串 t 相匹配。这里的“重新排列这些子字符串”并不是说子字符串内部相互的字符可以重新排列而是子字符串之间的顺序可以互换子字符串的字符顺序保持不变。