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

  (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. zk ui安装 (选装,页面查看zk的数据)

    # 使用WEB UI查看监控集群-zk ui安装 cd /usr/local git clone https://github.com/DeemOpen/zkui.git yum install -y ...

  2. 作业调度框架Quartz.NET-现学现用-02-任务监听 - 简书

    原文:作业调度框架Quartz.NET-现学现用-02-任务监听 - 简书 前言 任务调度系统并不是完美的,它会出现任务执行失败的情况.如果你需要处理任务失败后的逻辑,希望这篇笔记可以为你提供些帮助. ...

  3. static修饰的成员与非static修饰类的成员的区别

    ① 格式 : 1> static修饰的,称为静态成员,非static修饰的,称为非静态成员. ② 内存位置: 1>static修饰的,在方法区的静态区中,非static修饰的,在堆中的对象 ...

  4. 094、Swarm 中最重要的概念(Swarm01)

    参考https://www.cnblogs.com/CloudMan6/p/7845365.html   从主机层面来看,Docker Swarm 管理的是 Docker Host 集群.所以先来讨论 ...

  5. qt tableview列头背景颜色设置

    设置表列头背景颜色 QHeaderView::section { background: rgb(255, 255, 127); }

  6. Git命令之:git push

    保护版权:转自,http://www.yiibai.com/git/git_push.html

  7. TensorFlow基础与实战

    开源工具 TensorFlow:谷歌,C++.Python,Linux.Windows.Mac OS X.Andriod.iOS Caffe:加州大学,C++.Python.Matlab,Linux. ...

  8. Malloc与Free不调用构造函数与析构函数

    例子: #include "stdafx.h" #include <new> #include <iostream> using namespace std ...

  9. [PyQt5]动态显示matplotlib作图(一)

    完整实例 import sys from PyQt5.QtWidgets import QApplication, QMainWindow, QMenu, QVBoxLayout, QSizePoli ...

  10. 一个显示 OpenCV Mat 图像的自定义 Qt 控件

    今天学习 Qt 的时候顺手写了一个,包含一个头文件 qcvdisplay.h 和一个源文件 qcvdisplay.cpp,因为这是 qt 默认的文件命名方式,在 Qt Designer 中提升控件时会 ...