细节整理合集

一些错误

来源:P1772 [ZJOI2006] 物流运输

  • 在赋值 \(co[][]\) 数组的时候最好不要直接用 memset(co,0x3f,sizeof(co)) ,因为这样只能保证在相加极大值的时候不会爆,而 \(co[][]\) 在转移是乘上一个数,会导致爆 long long 或者 int
  • 注意怎么判断一个时间区间内一个点可不可用,例如 \(k\) 点在 \([l,r]\) 时间段不能用,那么我们现在时间区间为 \([i,j]\),判断为 \((i\le l\le j)||(i\le r\le j)||(l\le i,j\le r)\),不要像我一样少写一个调半个小时。想必不会有人跟我一样蠢
  • 因为这个变量名的命名很乱,所以要注意使用的变量名与其意义对应。某人又因为写错了一个变量,而样例里两个变量的值是一样的,结果上交直接爆 0。

来源:2023.8.8 正睿模拟赛 C题,二维树状数组

然后就是写的过程中发现:

  • char 爆完了,因为 char 的取值范围是 [-128,127] 的。
  • short 的内存爆了,只能拿 \(95pts\)(当然如果是 NOIP 估计直接爆炸),算了一下有 \(512MB\)
  • 只能用 unsigned char,但是一定要及其小心赋值的问题,其他方法见代码。
  • 一定要看清题目的输入顺序啊,我调这个又调了半个小时,还有变量不要打错了啊啊啊。

vector在操作之后,原有的地址可能会改变!!

具体可见我博客,或者见

来源: wzoi 2023.8.29 T2

代码巨简单,但是我一直没有发现我数组下标是负(居然可以正常运行没有报错!!就算报错也不是在数组上出错),后来出现了:

  • 长度为 \(9\) 的字符串遍历到第 \(5\) 个元素时报段错误。(估计是数组把字符串的内存给挤掉了)
  • 输出 set<>.size()\(1\),但是遍历 set 输出了 \(7\) 个元素。
  • 只用 memset 清空数组答案会变(当然了,负下标没有清空)。

综上所述,数组越界可能会出现任何问题(之前 vector 开小了在 OJ 上显示系统错误)。

\(\color{Red}{千万不要在考场上用一些没有用过常见英文单词做变量名或者函数名!!}\)

wzOI 2023.9.6 模拟赛T3 100->0。

血的教训,因为有一个数组用了 kill[],虽然本地可以编译并且所有样例都过了,但是在各大 OJ 上都是 CE。所以为什么不报错呢?真的服了。

赋值的运算是从右向左的

add:2023.9.7

noip 10连测round1:

f[o+1]=f[o]+1;//为什么不能换成 f[++o]=f[o-1]+1;f[++o]=f[o-1]
o++;
f[o+1]=f[o];
o++;

我表达了这样的疑惑,然后就忘记了这件事,然后在 prufer 序列的讨论区看见了,突然发现问题了。

我们设最开始的 oo1,那么第一个式子如果用 f[++o]=f[o-1]+1 的话就是 f[o1+1]=f[o1-1]+1 显然错误,下面的同理。

写函数时注意外变量和内变量的写法

不会描述,反正经常把 y 写成 x。

比如 P 1262,就因为

for(int y:f[x])
    if(!dfn[x])tarjan(y),low[x]=min(low[x],low[y]);
    else if(vis[y])low[x]=min(low[x],low[y]);

调了很久。

注意比较运算符和按位运算符的优先级

比较运算符的运算优先级高于按位运算符。

if(!vis[i]&&dis[i]<a[i]^a[x])//错误,因为先执行了dis[i]<a[i]
//正确为:
if(!vis[i]&&dis[i]<(a[i]^a[x]))

来源:P4826

注意:OI赛制编译时一定要在不同的环境下运行试试

2023.11.7

一场差点 AK 模拟赛,因为在 T3 中顺手使用了 gcd() 而编译既没有报错也能产生正确答案而 rank1->rank2,70->0(差点满了其实,有一个小细节没判导致小点全错)。

使用并查集时一定都要用 find()

2023.11.7

不能用单独的变量,防止成环而死循环。

P1892

const int N=1003;
int n,m,fa[N<<1];
inline int find(int x){return (x==fa[x]?x:fa[x]=find(fa[x]));}
int main(){
    n=read(),m=read();
    for(int i=1;i<=n;i++)fa[i]=i;
    for(int i=1;i<=m;i++){
        char c;cin>>c;
        int l=read(),r=read();
        if(c=='E'){
            if(!fa[l+n])fa[l+n]=r;
            else fa[find(fa[l+n])]=find(r);
            if(!fa[r+n])fa[r+n]=l;
            else fa[find(fa[r+n])]=find(l);
        }else
            fa[find(l)]=r;//这里的问题
    }
    int ans=0;
    for(int i=1;i<=n;i++)if(fa[i]==i)ans++;
    cout<<ans;
    return 0;
}

这看上去是一份人畜无害最多复杂度退化到 \(O(n^2)\) 的代码,因为 \(n\) 很小,按理来说应该是拿头都能过,可是一直显示 \(MLE\)

原因,r 没有取 find() 也没有让 find(l)find(r) 比较,导致可能成环而死循环爆栈。

hack 数据

3 3
F 1 2
F 2 1
F 1 3

广搜细节

加入队列后应该直接先标记而不是等到排到以后再标记,防止出现大量重复状态。
luogu P11215

#错误事例:排到以后再标记 TLE 55pts
a[x][y]=-3;
queue<pair<int,int> >Q;
while(!Q.empty())Q.pop();
Q.push({x,y});
while(!Q.empty()){
	int dx=Q.front().first,dy=Q.front().second;
	Q.pop();
	for(int ww=0;ww<4;ww++){
		int dxx=dx+fx[ww],dyy=dy+fy[ww];
		if(a[dxx][dyy]==-1)Q.push({dxx,dyy});
	}
	a[dx][dy]=-3;
}
#正确事例:加入前直接标记防止重复加入,100pts
a[x][y]=a[xx][yy]=-3;
Q.push({xx,yy});
while(!Q.empty()){
	int dx=Q.front().first,dy=Q.front().second;
	Q.pop();
	for(int ww=0;ww<4;ww++){
		int dxx=dx+fx[ww],dyy=dy+fy[ww];
		if(a[dxx][dyy]==-1)Q.push({dxx,dyy}),a[dxx][dyy]=-3;
	}
}
posted @ 2023-10-07 09:45  NBest  阅读(36)  评论(0)    收藏  举报