• OI比赛常数优化


    这是一篇玄学文章

    一、编译优化

    1 #pragma GCC optimize("O3")
    2 #pragma G++ optimize("O3")
    预处理开O3优化

    比赛时除非遇到常数很大可能会卡的暴力题否则一定不要用!玩火自焚!

    二、I/O优化

    核心:利用getchar()和putchar()这两个底层函数和位运算加速

    输入优化(超逼格写法)

     1 #include<cstdio>
     2 #include<cctype>
     3 using namespace std;
     4 int read()
     5 {
     6     int x=0,f=0;
     7     char c=getchar();
     8     while(!isdigit(c))
     9     {
    10         f|=c=='-';
    11         c=getchar();
    12     }
    13     while(isdigit(c))
    14     {
    15         x=(x<<3)+(x<<1)+(c^48);
    16         c=getchar();
    17     }
    18     return f?-x:x;
    19 }
    输入优化

    这里为什么可以用c^48代替c-48('0')呢?因为48的二进制是110000,后4位均为0,48~57('9')近在后四位后变化,所以^48可以用来代替-48且更快

    听说用fread更快但只能写文件,这里就不写代码了,通常比赛时使用上面的优化即可,有兴趣的读者可以查阅资料了解一下

    输出优化

    每次使用putchar()输出字符可加速输出

    实测递归+putchar()输出整数的速度比printf()快6倍!

    但不要写递归版……递归版的速度还慢于printf

    放上代码

    #include<cstdio>
    #include<cctype>
    using namespace std;
    #define re register int
    int stk[111],tt;
    void print(int x)
    {
        if(x==0)
            putchar('0');
        else
        {
            if(x<0)
                putchar('-'),x=-x;
            tt=0;
            while(x)
            {
                stk[++tt]=x%10;
                x/=10;
            }
            for(re i=tt;i;i--)
                putchar(stk[i]|48);
        }
    }
    输出优化

    格式控制直接手打putchar()即可

    stack[i]|48的正确性由输入优化的解释和或运算的定义显然可知

    三、寄存器变量

    需要大量运算的变量申请为寄存器变量,即register+类型名

    通常将循环变量设为寄存器变量

    另外将register int设为字符串常量可以简化代码,详见下面代码

    1 #define re register int
    2 int main()
    3 {
    4     for(re i=1;i<=999999;i++)
    5     return 0;
    6 }
    申请寄存器变量

    不要滥用register,一方面少量变量修改优化效果不明显,另一方面寄存器放不下变量时就会自动把变量放到内存里……

    四、取模优化

    适用于只有加减运算的题目

    int inc(int x,int v,int mod){x+=v;return x>=mod?x-mod:x;}//代替取模+
    int dec(int x,int v,int mod){x-=v;return x<0?x+mod:x;}//代替取模-
    取模优化

    五、memset,memcpy以及memmove

    memset(数组名+第一个操作数下标,0/-1,操作大小*类型所占字节数)

    memcpy(目标数组名+该数组第一个操作数下标,被copy数组名+该数组第一个操作数下标,操作大小*类型所占字节数)

    memmove(目标数组名+该数组第一个操作数下标,被清空数组名+该数组第一个操作数下标,操作大小*类型所占字节数)

    实例:

    1 //int是4个字节所以用<<2
    2 memset(a+l,0,r-l+1<<2);
    3 memcpy(a+l,b+l,r-l+1<<2);
    4 memmove(a+l,b+l,r-l+1<<2);
    memset,memcpy和remmove实例

    获取类型所占字节数方法:sizeof(类型名)

    六、正常的优化

    思路:减少运算及比较次数&用位运算代替四则运算

    七、程序框架

    将register int和long long缩写可以节省时间……用define就行

    另外多设一个INF

    #include<cstdio>
    #include<cctype>
    using namespace std;
    #define re register int
    #define ll long long
    const int INF=0x3f3f3f3f;
    int stk[111],tt;
    void print(int x)
    {
        if(x==0)
            putchar('0');
        else
        {
            if(x<0)
                putchar('-'),x=-x;
            tt=0;
            while(x)
            {
                stk[++tt]=x%10;
                x/=10;
            }
            for(re i=tt;i;i--)
                putchar(stk[i]|48);
        }
    }
    int read()
    {
        int x=0,f=0;
        char c=getchar();
        while(!isdigit(c))
        {
            f|=c=='-';
            c=getchar();
        }
        while(isdigit(c))
        {
            x=(x<<3)+(x<<1)+(c^48);
            c=getchar();
        }
        return f?-x:x;
    }
    int main()
    {
        return 0;
    }
    程序框架

    结束语

    此篇文章介绍的优化均已实测证明,下面是一些误传:

    1. 迷信inline?实测inline还要稍微慢上一丢丢……
    2. 前置++和后置++实测在单独语句时没有任何差别
    3. 用三目运算符(?:)代替if()else()?然而实测三目运算符比if()else()还要慢一些……
  • 相关阅读:
    Spring Cloud Hystrix Dashboard的使用 5.1.3
    Spring Cloud Hystrix 服务容错保护 5.1
    Spring Cloud Ribbon 客户端负载均衡 4.3
    Spring Cloud 如何实现服务间的调用 4.2.3
    hadoop3.1集成yarn ha
    hadoop3.1 hdfs的api使用
    hadoop3.1 ha高可用部署
    hadoop3.1 分布式集群部署
    hadoop3.1伪分布式部署
    KVM(八)使用 libvirt 迁移 QEMU/KVM 虚机和 Nova 虚机
  • 原文地址:https://www.cnblogs.com/LiHaozhe/p/9520216.html
Copyright © 2020-2023  润新知