簡單的卡常數【OI縮水版】

小哈里發表於2018-04-15

一、為什麼要卡常數?

這裡寫圖片描述

  • OI中資料結構與常數優化關係很大的
  • 如果你常數好可以暴力過資料結構題啦~
  • 如果你常數不好即使複雜度一樣也會被出題人卡~

二、常用的卡常數方法

1、卡IO(輸入輸出)

比較簡單的寫法:

int readint(){
    int op=1,x=0;  char ch=getchar();
    while(ch<'0' || ch>'9'){if(ch=='-')op=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return op*x;
}
void outint(int x){
    if(x<0){putchar('-');x=-x;}
    if(x>9)outint(x/10);
    putchar(x%10+'0');
}

比較奇怪的寫法

mmap

2、卡編譯

2.1 C++行內函數inline

由編譯器在編譯時會在主程式中把函式的內容直接展開替換,減少了記憶體訪問。(如果是遞迴可能會展開前幾層的運算吧?)

int max(int a, int b){return a>b?a:b;}//原函式
inline int max(int a, int b){return a>b?a:b;}//前面直接加inline就好了。
2.2 CPU暫存器變數register

對於一些頻繁使用的變數,可以宣告時加上該關鍵字,執行時可能會把該變數放到CPU暫存器中,只是可能,不保證有效。特別是你變數多的時候,一般還是丟到記憶體裡面的。
比較下面兩段程式:

register int a=0;
for(register int i=1;i<=999999999;i++)a++;
int a=0;
for(int i=1;i<=999999999;i++)a++;

優化:0.2826 second
不優化:1.944 second


3、卡計算

3.1 取模優化
佔坑待填,據說 https://loj.ac/article/327
3.2 加法優化

++i代替i++
1. 後置++需要儲存臨時變數以返回之前的值,在 STL 中非常慢。
2. 事實上,int的後置++ 在實測中也比前置++ 慢0.5倍左右(UOJ 上自定義測試)

3.3 陣列優化

1、不要開bool,所有bool改成char,int是最快的(原因不明)。
2、在最大值50000*50000的時候用unsigned代替long long
3、對於多維陣列,用到乘法優化定址

// Code A
for(i=1;i<=n;i++)
    ans+=A[x][y][z][i];
// Code B
int *p=A[x][y][z];
for(i=1;i<=n;i++)
    ans+=*(p+i);
3.4 判斷優化

if()else語句比()?():()語句要慢,逗號運算子比分號運算子要快。

3.5 結構優化

1.如果你要經常呼叫a[x],b[x],c[x]這樣的陣列,把她們寫在同一個結構體裡面會變快一些,比如f[x].a, f[x].b, f[x].c
2.指標比下標快。

3.7 歡迎補充

4、卡演算法/預處理

4.1 STL優化

STL非常慢,可以手寫。

4.2 倍增優化

倍增表小的開前面——定址會變快很多

4.3 Floyd初始化
for(int i=1;i<=n;i++)
    for(int j=1;j<=n;j++)
        gra[i][j]=inf
for(int i=1;i<=b;i++)
    gra[i][i]=0

是比

for(int i=1;i<=n;i++)
    for(int j=1;j<=n;j++)
    {
        if(i==j) gra[i][j]=0;
        else gra[i][j]=inf
    }    

快80%以上的,,因為要每次去比較。

4.4 迴圈展開

自己感受。。。

void Init_Array(int *dest, int n)
{
    int i;
    for(i = 0; i < n; i++)
        dest[i] = 0;
}
void Init_Array(int *dest, int n)
{
    int i;
    int limit = n - 3;
    for(i = 0; i < limit; i+= 4)//每次迭代處理4個元素
    {
        dest[i] = 0;
        dest[i + 1] = 0;
        dest[i + 2] = 0;
        dest[i + 3] = 0;
    }
    for(; i < n; i++)//將剩餘未處理的元素再依次初始化
        dest[i] = 0;
}
4.5 佔坑待填。

相關文章