注意:本文所介绍的优化并不是算法上的优化,那个就非常复杂了,不同题目有不同的优化。笔者要说的只是一些实用的常数优化小技巧,很简单,虽然效果可能不那么明显,但在对时间复杂度要求十分苛刻的时候,这些小的优化对于帮助你成功卡常也是十分重要的。那么我们让进入正题吧。

  (1)inline放在自定义函数定义前

   不要问为什么,加就行了!额,这个东西就是内联函数,好像可以让你的函数有机会被计算机执行得稍微快一点,一般放在使用次数比较多的小函数前,像二分会常用到的check(),为sort()定制的CMP()等等,但是递归函数和较大的函数编译器会自动忽略,当然主函数前就更不要放了。。。比如下面这个例子可以用: 

inline bool CMP(const int &a,const int &b){
  return a>b;
}

  (2)register放在变量定义前

     这个可以有机会把变量申请存储在CPU寄存器中成为寄存器变量然后跑得飞起但是CPU寄存器的内存是很小的,因此一般只用来定义赋值次数较多的单个变量(比如,循环变             量),而且似乎是不能定义成为全局变量的。

  (3)++i比i++快

     记住就行了,尽量用++i而不用i++,当然有特殊需要用i++时除外。

  (4)读入优化(很重要!)

  这是针对整数的。先介绍一下原理:读入一个数时把它当作字符读比当作一个数读快,或者说用getchar(),gets()一类读比用scanf("%d",&x)要快。而读入字符时本身就是这样读的,当然就不用优化了。不要问为什么快!一般会自定义一个read()函数来读取,写法有很多,先贴上最常见的写法:

inline int read()
{
int f=,x=; //f表示符号,1为正,-1为负
char ss=getchar();
while(ss<''||ss>''){if(ss=='-')f=-;ss=getchar();}//跳过数字前的空格等字符
while(ss>=''&&ss<=''){x=x*+ss-'';ss=getchar();}//读到下一位ss,就把已读到的乘10,相当于全部进一位,
                                  //为存ss留出空间
return f*x;
}
//使用时直接x=read(),相当于scanf("%d",&x);

   然而装逼是没有止境的,你也可以这样写:

inline int read()
{
int X=,w=; char ch=;//这个ch一定要赋初值,除了‘0’~‘9’(注意这里是字符)什么都可以,不然可能会出锅的。。。
while(!isdigit(ch)) {w|=ch=='-';ch=getchar();}
while(isdigit(ch)) X=(X<<)+(X<<)+(ch^),ch=getchar();
return w?-X:X;
}

   首先问题是isdight()是什么玩意儿?它是定义在cctype头文件中的一个函数,用于判断是否是整数。w|=ch=='-',其实相当于w=w|(ch=='-'),|(或)是C语言中的一个位运算符,如果a和b中有一个为1,结果就为1。w一开始等于0,而当ch=='-'成立时,表达式的值为1,0的二进制|1的二进制结果就是1,w就被赋值为1了,表示有负号。(X<<3)+(X<<1)=X*8+X*2=X*10,原因见后面。^(异或)也是位运算符,笔者没有仔细研究,不过可以肯定的是一个char型数字^48(0的ASCLL值)就等于它的int型数字,所以有(ch^48)一用法。要注意的是位运算符比加减乘除的优先级都要低,所以一定要加括号。

使用读入优化在数据规模较小时优势并不明显,但在数据规模很大,比如上百十万时,使用读入优化会比不使用的读取速度快上几倍,为你成功卡常&暴力骗分争取宝贵的时间。

事实上还有一种比读优都要快10%的读优,就是用fread(),但是一般情况下不至于这么苛刻吧,所以笔者就不多说了(其实是笔者不会)。

  (5)输出优化

  既然有读入优化,自然也有输出优化。只是输出优化应用机会很少(一般只输出几个数),只有在需要输出的答案较多时才可能会用到。原理同读入优化,把原本为整数的答案转为字符(串)形式后输出。例如输出一个int型变量x,一般会写:

printf("%d",x);

      而用输出优化就是:

inline void print(int x)
{
if(x<){putchar('-');x=-x;}
if(x>) print(x/);
putchar(x%+'');
}

(ps:由于笔者的粗心,输出优化代码前面打错了,特此更正)

  (6)使用位运算符<<与>>

  这两个东西是C语言中的位运算符,什么意思呢?不会的可以百度一下,简单来说就是一个数在二进制状态下向左(右)移几位(超出的位数舍弃)后的值。比如1<<2,意思是把1的二进制左移2位后得到的值。我们知道1的二进制是1(2),左移2位,就是100(2),也就是4。那么8>>1的值是多少呢?8=1000(2),右移一位就是100(2),也就是4。也许你会惊奇地发现a<<b就等于a*2^b,a>>b就等于a/2^b。没错!这就是我们要用到它的地方。当你写a=a/2时,你也可以写成a=a>>1;a=a*2也可以写成a=a<<1,等等。    

   那么,为什么我们非要用这个位运算符呢?因为在C语言中,位运算比起加减乘除等属于较底层的操作,加减乘除其实也是通过位运算实现的,算是一种把底层操作更高级地“打包”起来,就像高级语言是由机器语言转化而来的,执行时仍然要编译为机器语言,这中间当然会花费一些不必要的时间和空间,因此越底层的操作往往越快。并且,我们可以用1<<n很方便地表示2^n,在实际操作中很有用处。

-->最后,笔者还想提醒一点,据学长所说inline和register是两个非常玄学的东西,有时可能还会造成负优化。。。(好了我就是想说被卡了别找我)

  初次发表博文,希望能帮到大家,请多多指教.

2018-08-15

OI常用的常数优化小技巧的更多相关文章

  1. 嵌入式C语言优化小技巧

    嵌入式C语言优化小技巧 1 概述 嵌入式系统是指完成一种或几种特定功能的计算机系统,具有自动化程度高,响应速度快等优点,目前已广泛应用于消费电子,工业控制等领域.嵌入式系统受其使用的硬件以及运行环境的 ...

  2. .NET性能优化小技巧

    .NET 性能优化小技巧 Intro 之前做了短信发送速度的提升,在大师的指导下,发送短信的速度有了极大的提升,学到了一些提升 .NET 性能的一些小技巧 HttpClient 优化 关于使用 Htt ...

  3. 常用的一些javascript小技巧

    (转载)常用的一些javascript小技巧: http://bbs.blueidea.com/thread-2201069-1-1.html

  4. IT咨询顾问:一次吐血的项目救火 java或判断优化小技巧 asp.net core Session的测试使用心得 【.NET架构】BIM软件架构02:Web管控平台后台架构 NetCore入门篇:(十一)NetCore项目读取配置文件appsettings.json 使用LINQ生成Where的SQL语句 js_jquery_创建cookie有效期问题_时区问题

    IT咨询顾问:一次吐血的项目救火   年后的一个合作公司上线了一个子业务系统,对接公司内部的单点系统.我收到该公司的技术咨询:项目启动后没有规律的突然无法登录了,重新启动后,登录一断时间后又无法重新登 ...

  5. mysql优化小技巧

    对mysql优化时一个综合性的技术,主要包括 a: 表的设计合理化(符合3NF) b: 添加适当索引(index) [四种: 普通索引.主键索引.唯一索引unique.全文索引] c: 分表技术(水平 ...

  6. D3D9 优化小技巧

    此篇文章主要讲一些小技巧,针对前面转载的D3D9 GPU Hacks,我们可以做的一些优化. 在做延迟渲染或者其它需要深度的地方使用INTZ格式的纹理,这样可以直接对纹理进行操作,节省了显存和带宽,这 ...

  7. How Javascript works (Javascript工作原理) (十一) 渲染引擎及性能优化小技巧

    个人总结:读完这篇文章需要20分钟,这篇文章主要讲解了浏览器中引擎的渲染机制. DOMtree       ----|   |---->  RenderTree CSSOMtree  ----| ...

  8. JavaScript 工作原理之十一-渲染引擎及性能优化小技巧

    原文请查阅这里,略有删减,本文采用知识共享署名 4.0 国际许可协议共享,BY Troland. 本系列持续更新中,Github 地址请查阅这里. 这是 JavaScript 工作原理的第十一章. 迄 ...

  9. Spring Cloud OpenFeign 的 5 个优化小技巧!

    OpenFeign 是 Spring 官方推出的一种声明式服务调用和负载均衡组件.它的出现就是为了替代已经进入停更维护状态的 Feign(Netflix Feign),同时它也是 Spring 官方的 ...

随机推荐

  1. Oracle数据库跟踪存储过程

    1.[右击]该存储过程 ——>勾选[添加调试信息]——>点击[测试]选项 2.输入对应参数,点击下图左上角红框按钮,开始跟踪,可逐语句逐过程跟踪

  2. 洛谷 P1484 种树 题解

    题面 这是一道标准的带反悔贪心: 利用大根堆来维护最大值: 当选择了num[i]后,反悔了,反之选择选了num[i-1]和num[i+1]时获利便增加了num[i-1]+num[i+1]-num[i] ...

  3. 基于Caffe训练AlexNet模型

    数据集 1.准备数据集 1)下载训练和验证图片 ImageNet官网地址:http://www.image-net.org/signup.php?next=download-images (需用邮箱注 ...

  4. Ubantu 手动设置DSL连接

    参考链接:https://m.linuxidc.com/Linux/2015-07/119774.htm

  5. vue的v-model指令原理分析

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  6. SQLite3中自增主键相关知识总结,清零的方法、INTEGER PRIMARY KEY AUTOINCREMENT和rowid的使用

    这篇文章主要介绍了SQLite3中自增主键相关知识总结,清零的方法.INTEGER PRIMARY KEY AUTOINCREMENT和rowid的使用等,需要的朋友可以参考下 一.SQLite清空表 ...

  7. IIS下设置跨域访问问题--Access-Control-Allow-Origin 站点跨域请求的问题

    背景: 最近 开发中遇到新需求,把公司的OA系统迁移一套到小程序上面去 有些功能的信息是在小程序 查看 但是文件是在pc端上传的 例如:领导在外出办公 使用小程序查看xxxx.pdf文件  这个时候就 ...

  8. matlab 中figure的图像 抗锯齿

    linehandle = plot(xxxxxx); set( linehandle, 'linesmoothing', 'on' );

  9. SQL的基本操作(三)

    Hive基本SQL操作 Hive DDL(数据库定义语言) 1.数据库的基本操作 --展示所有数据库 show databases; --切换数据库 use database_name; /*创建数据 ...

  10. Spring学习之设计模式,动态代理和gclib动态代理

    传统的代理模式是静态代理,也就是在方法区域中写入方法. 而动态代理的作用是,不修改实现类的代码,能够在代码的前后或者抛出异常的前后执行某个方法. 动态代理类的实现 //Interface public ...