zoukankan      html  css  js  c++  java
  • 浅谈快读快写

    前言

    不用快读的卡常都是耍流氓 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;
    }
  • 相关阅读:
    Maven No sources to compile
    [ERROR] Failed to execute goal org.apache.maven.plugins:maven-assembly-plugin:2.4:single (make-assembly) on project hive-udf: Error reading assemblies: No assembly descriptors found. -> [Help 1]
    在使用maven时出现Invalid packaging for parent pom.xml, must be _pom_ but is _xxx类问题的处理
    blogs
    resouces
    Natural Language Processing with Python 1.1
    Fundamentals of Python: Preface
    移动互联网
    时间都去哪儿了
    凝思磐石安全操作系统官方版 下载
  • 原文地址:https://www.cnblogs.com/do-while-true/p/12319035.html
Copyright © 2011-2022 走看看