卡常
DuskDawn
·
2022-10-05 20:28:47
·
个人记录
\texttt{Faster!Faster!!Faster!!!}
怎样更快?
当你面对残酷的 \texttt{TLE} 却又不愿意承认自己的算法有问题时,卡常是一个很好的办法。
卡常又称卡常数、底层常数优化,是 \texttt{OI} 中一种针对程序基本操作进行空间或时间上优化的行为。
卡常第壹式——快读 & 快写
众所周知,字符输入输出比标准输入输出快得多。
快读和快写就是运用了这个原理。
快读模板:
template <typename T>
void read(T &x) {
x=0;
int f=1;
char ch=getchar();
while (!isdigit(ch)){
if (ch=='-'){
f=-1;
}
ch=getchar();
}
while(isdigit(ch)){
x=x*10+(ch-'0');
ch=getchar();
}
x*=f;
}
用法:
read(n);//输入并赋值
快写模板:
template <typename T>
void write(T x) {
if(x<0) {
putchar('-');
x=-x;
}
if(x>9) {
write(x/10);
}
putchar(x%10+'0');
}
用法:
write(n);//输出n
卡常第贰式——位运算
位运算是直接对数据在内存中的二进制数进行运算,速度自然比四则运算要快,能用就用。
不懂位运算的的看这里。
乘除法最好用位移代替:
2 \times 2 = 2 << 1,2 \times 10 = (2 << 1) + (2 << 3)
90 \div 2 = 90 >> 1,128 \div 16 = 128 >> 4
小知识:
& = bitand
| = bitor
^ = xor
&= = and_eq
|= = or_eq
^= = xor_eq
~ = compl
位运算的其他应用:
1.代替模运算
17 mod 2 = 17 & 1,45 mod 4 = 45 & 3,986 mod 16 = 986 & 15
2.快速幂
快速幂模板:
#include <iostream>
using namespace std;
long long b,p,k,ans=1,b1,p1;
int main(){
cin>>b>>p>>k;
b1=b;
p1=p;
while (p){//求b^p mod k
if (p&1){//&代替取模
ans*=b;
ans%=k;
}
b*=b;
b%=k;
p>>=1;//>>代替除法
}
cout<<b1<<'^'<<p1<<" mod "<<k<<'='<<ans;
return 0;
}
3.交换两个数的值
a^=b^=a^=b//请自行思考原理
卡常第叁式——\texttt{inline}
在函数之前加上 \texttt{inline} ,会使其变成内联函数,可以加快函数调用,但只适用于简单且调用频繁的函数。涉及递归、大的循环等很复杂的函数,编译器会自动忽略 \texttt{inline} 。
快读函数就可以加上 \texttt{inline} ,但有时 \texttt{inline} 会被忽略。
卡常第肆式——寄存器
假设你要拿草稿纸,一个在桌子上,一个在打印机里,你拿哪一张?
就近原则。
寄存器相较于内存离 CPU 更近,所以 CPU 可以更快地访问寄存器。
从工作原理上说,寄存器的工作原理比内存简单得多。
综上,寄存器与内存存在小差异。我们可以使用寄存器来提高访问速度,往往运用于经常访问的变量。
例如:
for (register int i=1;i<=1000000000;i++)
# 卡常第伍式——三目运算符
相较于 $\texttt{if-else}$,三目运算符的汇编指令更短。
在少量的运行中,二者的区别微乎其微;但运行次数庞大时, 三目运算符的优势便显现出来。
# 卡常第陆式——常数的声明
尽量将常数声明成常量:
`const int mod=1000000009;`
比
`int mod=1000000009;`
要快。
# 卡常第柒式——O2优化
经常听到 $\texttt{O2}$ 这一说法,代码实现为:
`#pragma GCC optimize(2)`
## 究极优化:
```cpp
#pragma GCC optimize(1)
#pragma GCC optimize(2)
#pragma GCC optimize(3)
#pragma GCC optimize("Ofast")
#pragma GCC optimize("inline")
#pragma GCC optimize("-fgcse")
#pragma GCC optimize("-fgcse-lm")
#pragma GCC optimize("-fipa-sra")
#pragma GCC optimize("-ftree-pre")
#pragma GCC optimize("-ftree-vrp")
#pragma GCC optimize("-fpeephole2")
#pragma GCC optimize("-ffast-math")
#pragma GCC optimize("-fsched-spec")
#pragma GCC optimize("unroll-loops")
#pragma GCC optimize("-falign-jumps")
#pragma GCC optimize("-falign-loops")
#pragma GCC optimize("-falign-labels")
#pragma GCC optimize("-fdevirtualize")
#pragma GCC optimize("-fcaller-saves")
#pragma GCC optimize("-fcrossjumping")
#pragma GCC optimize("-fthread-jumps")
#pragma GCC optimize("-funroll-loops")
#pragma GCC optimize("-fwhole-program")
#pragma GCC optimize("-freorder-blocks")
#pragma GCC optimize("-fschedule-insns")
#pragma GCC optimize("inline-functions")
#pragma GCC optimize("-ftree-tail-merge")
#pragma GCC optimize("-fschedule-insns2")
#pragma GCC optimize("-fstrict-aliasing")
#pragma GCC optimize("-fstrict-overflow")
#pragma GCC optimize("-falign-functions")
#pragma GCC optimize("-fcse-skip-blocks")
#pragma GCC optimize("-fcse-follow-jumps")
#pragma GCC optimize("-fsched-interblock")
#pragma GCC optimize("-fpartial-inlining")
#pragma GCC optimize("no-stack-protector")
#pragma GCC optimize("-freorder-functions")
#pragma GCC optimize("-findirect-inlining")
#pragma GCC optimize("-frerun-cse-after-loop")
#pragma GCC optimize("inline-small-functions")
#pragma GCC optimize("-finline-small-functions")
#pragma GCC optimize("-ftree-switch-conversion")
#pragma GCC optimize("-foptimize-sibling-calls")
#pragma GCC optimize("-fexpensive-optimizations")
#pragma GCC optimize("-funsafe-loop-optimizations")
#pragma GCC optimize("inline-functions-called-once")
#pragma GCC optimize("-fdelete-null-pointer-checks")
#pragma G++ optimize(1)
#pragma G++ optimize(2)
#pragma G++ optimize(3)
#pragma G++ optimize("Ofast")
#pragma G++ optimize("inline")
#pragma G++ optimize("-fgcse")
#pragma G++ optimize("-fgcse-lm")
#pragma G++ optimize("-fipa-sra")
#pragma G++ optimize("-ftree-pre")
#pragma G++ optimize("-ftree-vrp")
#pragma G++ optimize("-fpeephole2")
#pragma G++ optimize("-ffast-math")
#pragma G++ optimize("-fsched-spec")
#pragma G++ optimize("unroll-loops")
#pragma G++ optimize("-falign-jumps")
#pragma G++ optimize("-falign-loops")
#pragma G++ optimize("-falign-labels")
#pragma G++ optimize("-fdevirtualize")
#pragma G++ optimize("-fcaller-saves")
#pragma G++ optimize("-fcrossjumping")
#pragma G++ optimize("-fthread-jumps")
#pragma G++ optimize("-funroll-loops")
#pragma G++ optimize("-fwhole-program")
#pragma G++ optimize("-freorder-blocks")
#pragma G++ optimize("-fschedule-insns")
#pragma G++ optimize("inline-functions")
#pragma G++ optimize("-ftree-tail-merge")
#pragma G++ optimize("-fschedule-insns2")
#pragma G++ optimize("-fstrict-aliasing")
#pragma G++ optimize("-fstrict-overflow")
#pragma G++ optimize("-falign-functions")
#pragma G++ optimize("-fcse-skip-blocks")
#pragma G++ optimize("-fcse-follow-jumps")
#pragma G++ optimize("-fsched-interblock")
#pragma G++ optimize("-fpartial-inlining")
#pragma G++ optimize("no-stack-protector")
#pragma G++ optimize("-freorder-functions")
#pragma G++ optimize("-findirect-inlining")
#pragma G++ optimize("-frerun-cse-after-loop")
#pragma G++ optimize("inline-small-functions")
#pragma G++ optimize("-finline-small-functions")
#pragma G++ optimize("-ftree-switch-conversion")
#pragma G++ optimize("-foptimize-sibling-calls")
#pragma G++ optimize("-fexpensive-optimizations")
#pragma G++ optimize("-funsafe-loop-optimizations")
#pragma G++ optimize("inline-functions-called-once")
#pragma G++ optimize("-fdelete-null-pointer-checks")
```
快到飞起~~~
## 注意!!
- **该优化仅适用于 $\texttt{C++}$,其他语言(包括 $\texttt{C}$)可能会出现编译错误或负优化**。
- **上述优化在比赛、考试中禁用(你谷也不能用),仅适合日常骗分。**
# 卡常第捌式——其他卡常
1. 后置 ++ 需要保存临时变量以返回之前的值,在 STL 中非常慢。事实上,$\texttt{int}$ 的后置 ++ 在实测中也比前置 ++ 慢 0.5 倍左右。
1. 逗号比分号快。
1. $\texttt{bool}$ 很慢,尽量开 $\texttt{int}$(但是 $\texttt{bool}$ 比 $\texttt{int}$ 省空间)。
一些卡常在正规比赛中**禁用**。
**可以发现,卡常都是一些看着不起眼的优化,但它们确实对提高程序效率起到了至关重要的作用。**
>行了,你已经是世界上最快的~~男人~~OIer了。
by [hear](https://blog.csdn.net/sight_720/article/details/122919247)