程序玄学常数优化

Posted unnamed05

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了程序玄学常数优化相关的知识,希望对你有一定的参考价值。

一、读入优化

  读入时的速度cin<scanf<getchar

  我们可以用getchar()读入整数

inline int read(){
    int num=0;
    char c;
    while(isspace(c=get_char()));
    while(num=num*10+c-48,isdigit(c=get_char()));
    return num;
}

  fread是直接对二进制文件进行读入,速度更快

const int MAXBUF = 100000;
char buf[MAXBUF], *ps = buf, *pe = buf+1;
inline void rnext()
{
    if(++ps == pe)
        pe = (ps = buf)+fread(buf,sizeof(char),sizeof(buf)/sizeof(char),stdin);
}

template <class T>
inline bool in(T &ans)
{
    ans = 0;
    T f = 1;
    if(ps == pe) return false;//EOF
    do{
        rnext();
        if(- == *ps) f = -1;
    }while(!isdigit(*ps) && ps != pe);
    if(ps == pe) return false;//EOF
    do
    {
        ans = ans*10+*ps-48;
        rnext();
    }while(isdigit(*ps) && ps != pe);
    ans *= f;
    return true;
}

 二、运算优化

  1、位运算优化:乘上2的幂或除以2的幂时可以直接用位运算进行优化

  2、除法、取模优化:除法运算的耗时是乘法运算的几倍,能不用尽量不用,比如i/a>b可以以换成i>a*b

  3、浮点数除法优化:

    float a,b,c;
    init(a,b,c);
    a/=c;
    b/=c;

    可以换成

    float a,b,c;
    init(a,b,c);
    float d=1/c;
    a*=d;
    c*=d;

 三、针对cpu缓存的优化

    1、一维数组的数组大小尽量开成2的幂,高维数组每一维的数组大小最好都不要开成2的幂!(状压dp时要尤其注意)

    2、遍历数组时最好按数组存放顺序遍历

     For example  

    
  //first
  for(int i=0;i<n;i++) for(int j=0;j<m;j++) a[i][j]*=2;
    
  //second
  for(int i=0;i<m;i++) for(int j=0;j<n;j++) a[j][i]*=2;

    第一种比第二种效率快得多

   3、数组的索引也是需要时间的,特别是高位数组的索引寻地址效率很低,因此我们可以用指针来代替数组寻址

  

//first
int a[55][65][75][85];
int main()
{
     int *p=&a[0][0][0][0];
     for(int i1=0;i1<55;i1++)
        for(int i2=0;i2<65;i2++)
            for(int i3=0;i3<75;i3++)
                for(int i4=0;i4<85;i4++)
                       (*(p++))++;
}
//second
int a[55][65][75][85];
int main()
{
     for(int i1=0;i1<55;i1++)
     {
        int (*p)[65][75][85]=a[i1];
        for(int i2=0;i2<65;i2++)
            for(int i3=0;i3<75;i3++)
                for(int i4=0;i4<85;i4++)
                       p[i2][i3][i4]++;
      }
} 
//third
int a[55][65][75][85];
int main()
{
     for(int i1=0;i1<55;i1++)
        for(int i2=0;i2<65;i2++)
            for(int i3=0;i3<75;i3++)
                for(int i4=0;i4<85;i4++)
                       a[i1][i2][i3][i4]++
} 

    很明显,效率上第一种>第二种>第三种,但很多时候并不是单纯的按顺序访问数组,这种时候第二种写法(只需要对3维数组寻址)就派上用场了

     3、循环展开

      举一个很蠢的例子

int cnt=0;
for(int i=0;i<n;i++)
    cnt++;
int cnt1=0,cnt2=0,cnt3=0,cnt4=0;
for(int i=0;i<n;i+=4)
    cnt1++,cnt2++,cnt3++,cnt4++;
int cnt=cnt1+cnt2+cnt3+cnt4;

    第二种的效率是是一种的4倍

    这里有两点需要注意的

    (1)循环展开一般最多展开8重,再多的话反而会使效率降低

    (2)循环展开的各条语句一定要是无关的,比如

    

int cnt=0;
for(int i=0;i<n;i+=4)
    cnt++,cnt++,cnt++,cnt++;

    这样写效率没有显著提升(因为4条语句都要用到cnt,4条语句相关)





以上是关于程序玄学常数优化的主要内容,如果未能解决你的问题,请参考以下文章

trick合集

OI比赛常见优化

玄学优化

LightOJ 1098(均值不等式,整除分块玄学优化)

[科技]$Miller\_Rabin$ 和 $Pollard\_Rho$ 及各种玄学优化

各种各样的——玄学搜索