卡常數

卡常數

卡常數,又稱底層常數最佳化,是信息學競賽中一種針對程式基本操作進行空間或時間上最佳化的行為,與時間複雜度或剪枝有別。

也指程式雖然漸進時間複雜度可以接受,但是由於實現/算法本身的時間常數因子較大,使得無法在OI/ACM-ICPC等算法競賽規定的時限內運行結束。

基本介紹

  • 中文名:卡常數
  • 別名:卡常、底層常數最佳化
  • 適用領域:信息學競賽(OI,ACM-ICPC),程式設計套用
  • 套用學科:計算機
  • 使用前置技能:一定的代碼水平與對計算機機制的了解
  • 拼音:kǎ cháng shù
名詞解釋,套用方法,相關題目,

名詞解釋

卡常數,又稱底層常數最佳化,特指在OI/ACM-ICPC等算法競賽中針對程式基本操作進行的底層最佳化,一般在對程式性能要求較為嚴苛的題目或是在算法已經達到理論最優時間複雜度時使用,有時也用於非正解的強行最佳化。實現方法有使用register暫存器關鍵字、利用空間連續性使數組進入快取、輸入輸出最佳化等。
由於缺乏對系統底層的控制方法,Pascal、Python等語言較難進行卡常數。

套用方法

register關鍵字的使用
register是C++關鍵字,將其加在變數聲明前可以建議編譯器將變數直接放入暫存器中,從而大量減少該變數訪問時間。
即將形如
for(int i=1;i<=n;i++)
的語句改為
for(register int i=1;i<=n;i++)
該關鍵字只起到建議的作用,並不能保證變數一定被放入暫存器,且CPU中暫存器數量有限,建議將其加到循環變數等常用變數中,以免造成負最佳化。
該關鍵字從C++17起被棄用。
增強記憶體訪問連續性
CPU在運行時,會按照“當一個變數被訪問,其周圍的變數接下來很有可能會被訪問”的原則,將一定數量的變數存入高速快取。故在使用高維數組時,應儘量使最後一維變化連續。
如矩陣乘法中,做法
for(int i=1;i<=n;i++)
    for(int k=1;k<=p;k++)
        for(int j=1;j<=m;j++)
            ans[i][j]+=a[i][k]*b[k][j];
會比
for(int i=1;i<=n;i++)
    for(int j=1;j<=m;j++)
        for(int k=1;k<=p;k++)
            ans[i][j]+=a[i][k]*b[k][j];
要快,因為第一種做法使得b[k][j]的訪問相較於第二種更為連續。
輸入輸出最佳化
利用getchar/putchar函式速度較高的特性並省去scanf/printf中對類型的判斷,對整形讀入的方法。
也有針對浮點數的版本。
原理:用getchar與putchar函式對整形每一個十進制位進行操作。
讀入最佳化:
對於無符號整數:
void read(int &x)
{
    x=0;register char c=getchar();
    while(c<48||57<c) c=getchar();
    for(;48<=c&&c<=57;c=getchar()) x=x*10+(c&15);
}
使用時調用read(n);
對於有符號整數(避免在讀入-2147483648時溢出的方法):
int redi(void) {
  int f = 0;char ch, flag = 0;
  while(ch = getchar(), !isdigit(ch)) if(ch == '-') flag = 0xff;
  if (flag) {
   while (isdigit(ch)) f = f * 10 - ch + 48, ch = getchar();
  } else {
   while (isdigit(ch)) f = f * 10 + ch - 48, ch = getchar();
  }
  return f;
}
其他較高級方法
  1. 循環展開:將for循環每次增量變為四倍,每個循環體中同時進行4次操作,從而刺激CPU多個核心的並發運算。
  2. 指令集函式:使用CPU中自帶指令代替部分函式,起到超高速計算的效果。
  3. 卡馬克快速開平方取倒法:利用浮點數在記憶體中的儲存方式,找到了使牛頓疊代法初值精確度最接近精確值(著名的0x5f3759df)從而快速逼近1式的方法。
  4. fread/fwrite輸入輸出最佳化:利用fread/fwrite成片輸出最佳化getchar/putchar的輸入輸出二次最佳化版本,在輸入輸出量大的題目中效果較為明顯。
1式:
(無法在正文中打出)

相關題目

  1. Ynoi(由乃OI)系列:由著名數據結構大師nzhtl1477創作的一系列數據結構題目,因其對常數與時間複雜度的嚴格要求、極高的難度、優美而冗長的題面以及與題面毫不相關的題目著稱。大多使用數列分塊算法,但也不乏對線段樹、平衡樹、計算幾何等考點的考察。
  2. WC2017 挑戰:由著名的卡常數選手王逸松命題,卡常數界宗師級的題目。在2017年的冬令營上讓無數選手苦思冥想,並在其中提出了“松式基排”的概念。因此OI選手也將極其優秀的複雜度稱為O(wys)。

相關詞條

熱門詞條

聯絡我們