关于c++卡常
在oi题目中,我们往往需要不断优化使用的算法已在足够短的时间内得出答案。
但优化算法只是优化程序的一种方式,另一种方法卡常也同样非常重要
接下来我将介绍几种常见的卡常技巧
1.register,inline
register通过将变量放入寄存器,加速访问
inline则通过内联函数的方式,加速函数调用
通过如下代码进行测试
#include<bits/stdc++.h>
using namespace std;
time_t st,ed;
int main(){
st=clock();
for(int i=1;i<=1e9;i++);
ed=clock();
printf("%d ms \n",ed-st);
return 0;
}
#include<bits/stdc++.h>
using namespace std;
time_t st,ed;
int main(){
st=clock();
for(register int i=1;i<=1e9;i++);
ed=clock();
printf("%d ms \n",ed-st);
return 0;
}
第一次测试 | 第二次测试 | 第三次测试 | |
---|---|---|---|
无register | 1210 ms | 1210 ms | 1190 ms |
register | 489 ms | 479 ms | 480 ms |
可以看到register在大数据规模下优化效果非常明显
接下来测试inline
#include<bits/stdc++.h>
using namespace std;
int n,sum;
time_t st,ed;
void add(){
sum++;
}
int main(){
st=clock();
for(int i=1;i<=1e9;i++)add();
ed=clock();
printf("%d ms \n",ed-st);
return 0;
}
#include<bits/stdc++.h>
using namespace std;
int n,sum;
time_t st,ed;
inline void add(){
sum++;
}
int main(){
st=clock();
for(int i=1;i<=1e9;i++)add();
ed=clock();
printf("%d ms \n",ed-st);
return 0;
}
第一次测试 | 第二次测试 | 第三次测试 | |
---|---|---|---|
无inline | 413 ms | 403 ms | 405 ms |
inline | 340 ms | 348 ms | 352 ms |
(已经减去for循环用时)
inline的原理为将函数直接在程序中展开,所以对复杂函数和递归函数等效果不好
2.输入输出
快读可以大大提升读入的速度,是卡常必备
#include<bits/stdc++.h>
using namespace std;
clock_t st,ed;
void write(int x){
if(x>=10)write(x/10);
putchar(x%10+'0');
}
int main(){
freopen(".out","w",stdout);
st=clock();
for(int i=1;i<=1e6;i++)cout<<i;
ed=clock();
printf("\n%d ms\n",ed-st);
st=clock();
for(int i=1;i<=1e6;i++)printf("%d",i);
ed=clock();
printf("\n%d ms\n",ed-st);
st=clock();
for(int i=1;i<=1e6;i++)write(i);
ed=clock();
printf("\n%d ms\n",ed-st);
return 0;
}
第一次测试 | 第二次测试 | 第三次测试 | |
---|---|---|---|
cout | 64 ms | 63 ms | 57 ms |
printf | 1432 ms | 1434 ms | 1449 ms |
快写 | 150 ms | 140 ms | 148 ms |
#include<bits/stdc++.h>
using namespace std;
clock_t st,ed;
inline int read(){
int x=0;char ch=getchar();
while(ch<'0' || ch>'9')ch=getchar();
while(ch>='0' && ch<='9')x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
return x;
}
int main(){
freopen(".in","r",stdin);
st=clock();
for(int i=1;i<=1e6;i++)cin>>i;
ed=clock();
printf("\n%d ms\n",ed-st);
st=clock();
for(int i=1;i<=1e6;i++)scanf("%d",&i);
ed=clock();
printf("\n%d ms\n",ed-st);
st=clock();
for(int i=1;i<=1e6;i++)i=read();
ed=clock();
printf("\n%d ms\n",ed-st);
return 0;
}
第一次测试 | 第二次测试 | 第三次测试 | |
---|---|---|---|
cin | 650 ms | 660 ms | 649 ms |
scanf | 471 ms | 476 ms | 473 ms |
快读 | 150 ms | 156 ms | 160 ms |
可以看到快读在大数据下远远比scanf快,非常好用
但是在输出方面cout却比快写快,不太懂
3.取模运算
常值取模远比变量取模快,所以在取模时可以尽量用常值
#include<bits/stdc++.h>
using namespace std;
int mod1=1e9+7;
const int mod2=1e9+7;
clock_t st,ed;
int sum=1;
int main(){
st=clock();
for(int i=1;i<=1e8;i++)sum=(sum<<1)%mod1;
ed=clock();
printf("%d ms\n",ed-st-120);//120为位运算和for平均用时
st=clock();
for(int i=1;i<=1e8;i++)sum=(sum<<1)%mod2;
ed=clock();
printf("%d ms\n",ed-st-120);
return 0;
}
第一次测试 | 第二次测试 | 第三次测试 | |
---|---|---|---|
变量 | 629 ms | 689 ms | 639 ms |
常值 | 221 ms | 280 ms | 230 ms |
这就是常用的卡常技巧了,其他有些技巧经测试效果不大,所以没有放上来
本文作者:kent
本文链接:https://www.cnblogs.com/kentsbk/p/17611706.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步