写代码的一些小技巧&错题本(持续更新)

对double类型数组初始化:

无穷大0x42;无穷小0xc2。

模板类的read函数:

防止读longlong类型的数字时爆int

template<class Type>
inline Type read(void){
    Type x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return f*x;
}

读int类时int a=read<int>();,读longlong类时LL a=read<LL>();。贼好用。

线段树防写炸

在pushdown的时候,把更新子节点的值写进一个函数,在Update的时候也能用,防止手抽写炸。

inline void Add(int o,int v){
	add[o]+=v;
	sum[o]+=len[o]*v;
	minv[o]+=v;
	maxv[o]+=v;
	return;
}

inline void pushdown(int o){
	if(!add[o])return;
	Add(lson,add[o]);
	Add(rson,add[o]);
	add[o]=0;
}

inline void Update(int o,int l,int r,int ql,int qr,int v){
	if(ql<=l&&r<=qr){Add(o,v);return;}
	//Do something
}

滚动数组

可以开两个数组f和g,f表示当前i阶段的DP数组,g表示i-1阶段的DP数组。

for(register int i=1;i<=n;++i,swap(f,g))//转移
{
    //do something
}

树上求链交

求链(a,b)与(c,d)的交。

\(c_1=lca(a,b), c_2=lca(c,d)\),且排序后\(dep[c_1]\leq dep[c_2]\)

\(d_1 = lca(a,c), d_2 = lca(a,d), d_3 = lca(b,c), d_4 = lca(b,d)\),且排序后\(dep[d_1]\leq dep[d_2] \leq dep[d_3]\leq dep[d_4]\).

两条链有交当且仅当\(dep[c_1]\leq dep[d_1]\)\(dep[c_2] \leq dep[d_3]\),此时\(d_3\)\(d_4\)是两条链的交。

Splay函数

注意在Splay函数的最后写一行update(x),否则有可能会有未知错误。

inline void splay(int x, int goal) {
    for (int f; (f = fa[x]) != goal; rotate(x))
        if (fa[f] != goal) rotate(get(x) == get(f) ? f : x);
    if (!goal) root = x;
    update(x);
}

multiset的erase函数

multiset是可重集,但是erase函数却有一个小坑。就是如果erase函数传参是传的是“数值\(val\)”,它就会将集合中所有\(val\)全部删除。

但是如果传一个迭代器,它就只会删除一个元素。

注意题目中的限制

有一道题是这样规定的:\(0\leq k< n\),如果这样规定,那么\(k\)就不能等于\(n\)。一定要注意这样的小细节。

用单调队列实现决策单调性优化DP

注意在判断 \(i\) 是否是最优决策的时候用的是小于等于还是小于

如果用的是小于,注意特判 \(i\) 不是任何点的最优决策的情况。

int pos = -1;
while (hh <= tt && f[i] + w(i + 1, q[tt].l) < f[q[tt].p] + w(q[tt].p + 1, q[tt].l)) {
    pos = q[tt].l;
    -- tt;
}
if (hh <= tt) {
    if (f[q[tt].p] + w(q[tt].p + 1, q[tt].r) > f[i] + w(i + 1, q[tt].r)) {
        int l = q[tt].l, r = q[tt].r;
        while (l < r) {
            int mid = (l + r) >> 1;
            if (f[i] + w(i + 1, mid) < f[q[tt].p] + w(q[tt].p + 1, mid)) r = mid;
            else l = mid + 1;
        }
        pos = l;
        q[tt].r = pos - 1;
    }
}
if (pos != -1)
    q[++ tt] = Node(i, pos, n);

KMP算法

KMP算法在算法开始之前需要保证nxt数组是空的。所以如果多次用到nxt数组,注意清空。

读入 n or m?

在读入的时候一定要看清是读入 \(n\) 还是读入 \(m\),特别是当样例中的 \(n\)\(m\) 相同的时候。

注意空间复杂度

有时候在做题的时候,可能会着重考虑时间复杂度,而忽略的空间复杂度,导致最终写出来的程序由于空间过大而得到很低的分数。

做题前要看空间限制,如果是 256MB 及以下就要小心了!

乘法要注意 long long

int 类型的乘法一定要注意是否强制类型转换成 long long 类型。

O(1) 时间内实现 long long 乘法取模

LL mult(LL a, LL b) {
    return (a * b - (LL)((long double)a / P * b) * P + P) % P;
}
posted @ 2018-10-14 21:26  蓝田日暖玉生烟  阅读(542)  评论(0编辑  收藏  举报