关于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

这就是常用的卡常技巧了,其他有些技巧经测试效果不大,所以没有放上来

posted @ 2023-08-08 15:15  Kent530  阅读(318)  评论(0编辑  收藏  举报