浅谈快读快写

前言

不用快读的卡常都是耍流氓 by do_while_true

众所周知,在一些比较高档次的题中有时候毒瘤出题人会卡时间复杂度,或者出一些比较大的样例,从而激励我们不断地优化程序,但是有些OIer想不出更好的程序 其实就是太菜,可是又想尽可能地多拿分,那应该怎么办呢?这里就需要OIer进行卡常了

而输入输出的优化则是卡常的一个特别好用的方法

正篇

1.cin及cout

众所周知,cin,cout是特别慢的

可是为什么cin,cout会比其它的输入输出慢很多呢

cin,cout之所以效率低,是因为先把要输出的东西存入缓冲区,再输出,导致效率降低,而这段语句可以来打消iostream的输入输出缓存,可以节省许多时间

参考于这篇文章

那么我们能不能让cin,cout跑得更快一点呢?

答案是能的!

你只需要加上这个东西

ios::sync_with_stdio(false);

cin,cout就能跑得很快了

2.scanf和printf

scanf和printf相比大家也是非常熟悉了,它们能跑得比cin和cout快几十倍甚至几百倍

如果按照Part1的方式进行优化的话,scanf和printf就与优化后的cin和cout就差不多快了

但是由于大多数人背不过上面那个语句,相信很多人都是习惯于用scanf和printf的

3.快读快写

可是遇到比较毒瘤的数据,或者我们用其他方式卡常已经不能再快了,如果题目中的输入或者输出数据比较多的话,我们就可以用快读和快写进行优化了

首先,众所周知

getchar和putchar要比cin cout scanf printf 要快多了

据教练说是它一次只处理一个字节所以快

所以我们把int的每一位当作字符来处理,就能让输入输出变得特别快了

inline int read()
{
    int r=0,w=1;
    //r是存的这个数的绝对值 w是存的这个数是正数还是负数
    char ch=getchar();//ch为当前读入的字符
    while(ch<‘0‘||ch>‘9‘)//如果当前读入的字符不是数字,就一直读入,直到读入的是数字为止
       {
        if(ch==‘-‘) w=-1;//如果读到了‘-‘,就说明这是个负数
        ch=getchar();
       }
    //运行到这里时ch里面一定是个整数
    while(ch>=‘0‘&&ch<=‘9‘)//当读入的字符是数字时一直读入
       {
        r=r*10+ch-‘0‘;//存入当前这个数字,由于ch是个字符,所以存入的时候要减去字符0的ASCLL码
        ch=getchar();
       }
    return r*w;
}

实际上,这份快读还能优化的更快,众所周知,在C++中位运算要比直接调用数字快,所以说我们把其中所有设计到数字的都转化为位运算

Code:

//快读
#include<iostream>
#include<cstdio>
using namespace std;
inline int read()
{
    int r=0,w=1;
    //r是存的这个数的绝对值 w是存的这个数是正数还是负数
    char ch=getchar();//ch为当前读入的字符
    while(ch<‘0‘||ch>‘9‘)//如果当前读入的字符不是数字,就一直读入,直到读入的是数字为止
       {
        if(ch==‘-‘) w=-1;//如果读到了‘-‘,就说明这是个负数
        ch=getchar();
       }
    //运行到这里时ch里面一定是个整数
    while(ch>=‘0‘&&ch<=‘9‘)//当读入的字符是数字时一直读入
       {
        r=r*(1<<3)+r*(1<<1)+ch-(1<<4)-(1<<5);//存入当前这个数字,由于ch是个字符,所以存入的时候要减去字符0的ASCLL码
        //1<<3是8,1<<1是2,加起来就是10   1<<4是16,1<<5是32,加起来就是0的ASCLL码48
        ch=getchar();
       }
    return r*w;
}
int main()
{
   int n=read();
    return 0;
}

快写也同理,把一个int从低到高存在一个char数组里,再把char数组从低到高输出

inline void write(int x)
{
    char ch[20];
    int len=0;
    //ch里面存的是从低到高的数字的ASCLL码 len是数组长度
    if(x<0)//如果x是负数,那么先输出负号,再把x变成正数
      {
        putchar(‘-‘);
        x=~x+1;//x=~x+1;就等同于x=-x;
      }
    while(x>0)//当x>0的时候每次把x的最低位取出
       {
        ch[len++]=x%10+‘0‘;//取出最低位存到ch数组里面 因为ch是字符数组,所以要加上0的ASCLL码
        x/=10;//砍掉最低位
       }
    for(int i=len-1;i>=0;i--)//因为ch是从低到高存的x的绝对值,又因为要从高到低输出,所以倒着循环ch数组输出
       putchar(ch[i]);//输出从高到低的每一位
    return ;
} 

显然,细心的小伙伴读程后会发现,这个程序处理不了当x=0时的情况,也就是说如果我们在主程序里面直接

write(0);

它会什么也不输出

所以我们需要特判,但实际上,我们只需要把while改成do while就可以了,这样就能保证ch数组的存入一定会进行,也就能把x=0的特殊情况给排除掉了

最后再处理一下所有的位运算

Code:

//快写
#include<iostream>
#include<cstdio>
using namespace std;
inline void write(int x)
{
    char ch[20];
    int len=0;
    //ch里面存的是从低到高的数字的ASCLL码 len是数组长度
    if(x<0)//如果x是负数,那么先输出负号,再把x变成正数
      {
        putchar((1<<5)+(1<<3)+(1<<2)+1);
        //(1<<5)+(1<<3)+(1<<2)+1就是‘-‘的ASCLL码值
        x=~x+1;//x=~x+1;就等同于x=-x;
      }
    do//用do while可以防止x=0的特殊情况
      {
        ch[len++]=x%10+(1<<4)+(1<<5);//取出最低位存到ch数组里面 因为ch是字符数组,所以要加上0的ASCLL码
        x/=10;//砍掉最低位
      }while(x>0);//当x>0的时候每次把x的最低位取出
    for(int i=len-1;i>=0;i--)//因为ch是从低到高存的x的绝对值,又因为要从高到低输出,所以倒着循环ch数组输出
       putchar(ch[i]);//输出从高到低的每一位
    return ;
}
int main()
{
    int n;
    cin>>n;
    write(n);
    return 0;
}

后记

然而在考场上,因为我们的程序只能最后统一评测,并不像ACM赛制那样快乐,所以我们一定要尽可能地优化自己的程序,多测测大样例,看看能不能卡进要求的时间限制。如果尽自己所能还是卡不进那个时间限制,就要调整策略,去多花时间打正解还是多拿部分分偏分。保持心态,才是最重要的

本文参考资料

解决cin,cout速度过慢问题

C++的常用输入及其优化以及注意事项 - 明依 - 博客园

当然本文的代码和文字都是我辛辛苦苦码出来的qwq

另附 快读快写完整版本

#include<iostream>
#include<cstdio>
using namespace std;
inline int read()
{
    int r=0,w=1;
    char ch=getchar();
    while(ch<‘0‘||ch>‘9‘)
       {
        if(ch==‘-‘) w=-1;
        ch=getchar();
       }
    while(ch>=‘0‘&&ch<=‘9‘)
       {
        r=r*(1<<3)+r*(1<<1)+ch-(1<<4)-(1<<5);
        ch=getchar();
       }
    return r*w;
}
inline void write(int x)
{
    char ch[20];
    int len=0;
    if(x<0)
      {
        putchar((1<<5)+(1<<3)+(1<<2)+1);
        x=~x+1;
      }
    do
      {
        ch[len++]=x%10+(1<<4)+(1<<5);
        x/=10;
      }while(x>0);
    for(int i=len-1;i>=0;i--)
       putchar(ch[i]);
    return ;
}
int main()
{
    write(read());
    return 0;
}

原文地址:https://www.cnblogs.com/do-while-true/p/12319035.html

时间: 2024-10-11 07:52:06

浅谈快读快写的相关文章

卡常三连(快读快写+re)

快读: 1 inline int in() 2 { 3 char ch; 4 int a=0; 5 while(!(((ch=getchar())>='0')&&(ch<='9'))); 6 a*=10;a+=ch-'0'; 7 while(((ch=getchar())>='0')&&(ch<='9'))a*=10,a+=ch-'0'; 8 return a; 9 } 快写: inline void out(int a) { if(a>=10

快读快输

\(code :\) template<typename T> inline void read(T &x) { x=0;char c=getchar();bool flag=false; while(!isdigit(c)){if(c=='-')flag=true;c=getchar();} while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();} if(flag)x=-x; } template<ty

浅谈质因数分解

浅谈质因数分解 ->part 1: 算数基本定理: 任何一个大于1的正整数都能唯一分解为有限个质数的乘积,可写作: \[N=\prod_{i=1}^m p_i^ {c_i}\] 其中\(c_i\)都是正整数,\(p_i\)都是质数,且满足\(p_1<p_2<-<p_m\) ->part 2: 分解方法: 试除法 结合质数判定的"试除法"和质数筛选的"\(Eratosthenes\) 筛法",我们可以扫描 \(2-\sqrt N\)的每个

[模板]快读

此文为博主原创题解,转载时请通知博主,并把原文链接放在正文醒目位置. 快读=.= 嗯 是个很重要的东西 快读的模板是@bwx写的 同时也推荐她的博客ovo http://www.cnblogs.com/shingen/ 然后也没好解释的了 每次题目数据较大的时候码上就是 1 inline int read(){ 2 char ch, c; 3 int res = 0; 4 while (ch = getchar(), ch < '0' || ch > '9') c = ch; 5 res =

浅谈javascript单体【读javascript设计模式第五章节单体有感】

单体,整个运行环境就独有一份,最简单的一种单体就是一个把所有属性和方法都集中在一起的对象,区别于一般的字面量对象,一般字面量对象是对一个物体的描述,集合该物体所具有的一些属性和方法,而单体则包含更多的些逻辑在里面,单体的好处有,划分命名空间,如果用来作为网页包装器,可以使得页面所有变量都封装在一个对象里,大幅度减小网页里的全局变量, 代码如: common.js (function(wz){ $.extend({ init:function(){ var self = this; this.bi

浅谈javascript继承【读javascript设计模式第四章节继承有感】

javascript继承,无任是类式继承,原型式继承还是渗元式继承都是通过不同方法去围绕着prototype转,简单分析下三种不同继承方法是如何围绕prototype转的 一:类似继承,先上关键代码 function extend(subClass,supClass){ var fn = function(){}; fn.prototype = supClass.prototype; subClass.prototype = new fn(); subClass.prototype.constr

双极性正弦脉冲快读调制

双极性正弦脉冲快读调制 采用正弦脉冲宽度调制技术SPWM(Sinusoidal Pulse Width Modulation)是减少滤波器尺寸.获得高质量正弦波的有效手段. 一.      SPWM基本原理 采样控制理论有一个重要的原理—冲量等效原理:大小.波形不相同的窄脉冲变量作用于惯性系统时,只要它们的冲量(面积),即变量对时间的积分相等,其作用效果相同.换而言之,无论冲量的表现形式如何,只要是冲量等效的脉冲作用在惯性系统上,惯性系统的输出或响应是基本. 二.      双极性正弦脉冲宽度调

修改快读使其不提示更新。

一直用快读看小说....好浪费时间的说,最近快读更新版本了.TT 竟然有广告,首页有文章里面还有,太恶心了.果断转老版的,可老版每次更新就提示更新,我就想着能不能修改一下,能让它不提示就好啦. 开始百度,如何反编译apk文件,发现了一个好的工具.apktool,可以反编译,编译apk文件(http://apktool.shoujifans.com/2014/09/20.html)apktool这个挺好用的,在手机上也是可以是用的,棒棒的. 然后,把update文件删了........ 咦,空格变

快读knowledge

学长的奇怪快读fread函数好毒瘤 1 #define R register 2 #define getc() (S == T && (T = (S = B) + fread(B, 1, 1 << 15, stdin), S == T) ? EOF : *S++) 3 #define dmax(_a, _b) ((_a) > (_b) ? (_a) : (_b)) 4 #define dmin(_a, _b) ((_a) < (_b) ? (_a) : (_b))