卡常小寄巧

由于主播最近做 Ynoi 做多了,卡常卡的有点魔怔,所以写一下这个。


读入输出

我常用的是 cin/cout,不怎么用 printf/scanf

  • 关掉同步流(常用手法)
  • 多询问的时候,换行不要用 endl,用 \nendl 会附加清空缓存区的时间。
  • 数据量大或者时限紧的时候手写快读快写。
正常快读快写
inline int read(){
	int x=0,y=1;
	char ch=getchar();
	while (ch>'9'||ch<'0')y=(ch=='-')?-1:1,ch=getchar();
	while (ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
	return x*y;
}
inline void print(int x){
	if (x>9)print(x/10);
	putchar(x%10+'0');
	return;
}

只要不遇到恶心出题人给你每行后面加一千个空格就不会出大问题。
一般来说加了这俩就够了,但是 lxl 的题可能不太够,所以就用这个。

更 nb 的 fread
struct IO{
    static const int S=1<<21;
    char buf[S],*p1,*p2;int st[105],Top;
    ~IO(){clear();}
    inline void clear(){fwrite(buf,1,Top,stdout);Top=0;}
    inline void pc(const char c){Top==S&&(clear(),0);buf[Top++]=c;}
    inline char gc(){return p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++;}
    inline IO&operator >> (char&x){while(x=gc(),x==' '||x=='\n'||x=='\r');return *this;}
    template<typename T>inline IO&operator >> (T&x){
        x=0;bool f=0;char ch=gc();
       while(!isdigit(ch)){if(ch=='-') f^=1;ch=gc();}
        while(isdigit(ch)) x=(x<<3)+(x<<1)+ch-'0',ch=gc();
        f?x=-x:0;return *this;
    }
    inline IO&operator << (const char c){pc(c);return *this;}
    template<typename T>inline IO&operator << (T x){
        if(x<0) pc('-'),x=-x;
        do{st[++st[0]]=x%10,x/=10;}while(x);
        while(st[0]) pc('0'+st[st[0]--]);return *this;
    }
}fin,fout;
从别人那贺过来的 fread
namespace fastio{
	#define FILE_SIZE 1<<23
	char rbuf[FILE_SIZE],*p1=rbuf,*p2=rbuf,wbuf[FILE_SIZE],*p3=wbuf;
	inline char getc(){return p1==p2&&(p2=(p1=rbuf)+fread(rbuf,1,FILE_SIZE,stdin),p1==p2)?-1:*p1++;}
	inline void putc(char x){(*p3++=x);}
	template<typename T> void read(T &x){
		x=0;char c=getchar();T neg=0;
		while(!isdigit(c)) neg|=!(c^'-'),c=getchar();
		while(isdigit(c)) x=(x<<3)+(x<<1)+(c^48),c=getchar();
		if(neg) x=(~x)+1;
	}
	template<typename T> void recursive_print(T x){if(!x) return;recursive_print(x/10);putc(x%10^48);}
	template<typename T> void print(T x){if(!x) putc('0');if(x<0) putc('-'),x=~x+1;recursive_print(x);}
	void print_final(){fwrite(wbuf,1,p3-wbuf,stdout);}
}

https://www.cnblogs.com/tzcwk/p/kc.html 拿的。

其实 Ynoi 写 fread 是不是已经成传统了来着。
这俩差多少我也没测过(目移)
有时候我会去题解里抄一个快读下来什么的(目移)

计算,变量,函数

  • long long 运算速度比 int 慢一点,所以要卡的时候先把 #define int long long 去掉,能避免 ll 运算(特别是乘法和取模)就避免掉。
  • 如果数据范围允许,可以把一些 int 改成 short
  • 在一些情况下(比如求数列和)可以避免加一个取模一次,全加完再取一次模会更快。
  • 取模运算很慢,所以加减法的取模不要用 (a+b)%mod。改成加减法会更快。
取模优化
inline int add(int x,int y){
    return x+y>=mod?x+y-mod:x+y;
}
inline int del(int x,int y){
    return x-y<0?x-y+mod:x-y;
}
  • for 里的变量改成 register int
  • 在函数前面加 inline
  • 传参数和数组的时候用 const int & 而不是 int
  • 对于没有负数的变量可以开 unsigned
  • 赋值操作改格式,比如 int a=0; 改成 int a(0);(这一条不知道有没有效果)
  • 一些判断语句改用三目运算符(没测过,不知道效果)if(?)?; 改成 (?)&&(?);
  • 循环展开。小矩乘不写循环,语句比较小的(比如 for(int i=0;i<2;i++))也把循环拆掉。一般来说循环展开 4 层左右就够了。
  • 调整数组访问的顺序,顺序访问数组比随机访问快很多。可以调整多维数组下标的顺序,或者改变循环访问的顺序(尤其在矩乘中)
  • a++ 改成 ++a

位运算

  • swap(a,b)\(\to\)x^=y^=x^=y
  • -x\(\to\)~x+1
  • abs(x)\(\to\)x^(~(x>>31)+1)+(x>>31)
  • x%2==1\(\to\)x&1
  • x%2==0\(\to\)~x&1
  • 乘除 2 的幂次用左移或右移代替。

对于 STL 库

  • push_back 改成 emplace_back(不清楚效果)
  • lower_bound/upper_bound 改用手写二分。
  • set/map 常数比较大,遇到卡这俩的题换个做法或者手写吧。
  • sort 对排的比较好的数组常数大,可以先打乱再排(不清楚效果)
  • 如果还不行可以对值域小的数组用基数排序。
  • memcpy 比循环复制快。
  • memsetsizeof(a) 改成 (n+5)*sizeof(int)(对于需要清空的比较少的时候)
  • __builtin 很好用,本质其实是位运算,很快。
__builtin 一家
__builtin_ctz(unsigned int x);//求 x 二进制末尾 0 的数量
__builtin_clz(unsigned int x);//求 x 二进制前导 0 的数量
__builtin_ffs(unsigned int x);//求 x 二进制末位 1 的位置
__builtin_popcount(unsigned int x);//求 x 二进制 1 的个数
__builtin_parity(unsigned int x);//求 x 二进制 1 的个数的奇偶性

其他

  • 线段树启用底层分块和底层循环,会快一些。
  • 提前线性求逆元。
  • NTT 预先处理原根的幂。
  • 分块可以调一调快长,一般有用。
  • 搜索的时候 vis 不要次次清空,可以用不同的值重复覆盖标记减少清空次数。
  • 建图用链式前向星,少用 vector

最后祝广大 OIer 早日脱离卡常苦海。

posted @ 2025-05-07 15:31  Xuan_qwq  阅读(52)  评论(0)    收藏  举报