1. 程式人生 > >做OI題時的一些常用的常數優化小技巧

做OI題時的一些常用的常數優化小技巧

輸出 通過 十分 getch 執行 microsoft 次數 技巧 數字

  註意:本文所介紹的優化並不是算法上的優化,那個就非常復雜了,不同題目有不同的優化。筆者要說的只是一些實用的常數優化小技巧,很簡單,雖然效果可能不那麽明顯,但在對時間復雜度要求十分苛刻的時候,這些小的優化對於幫助你成功卡常也是十分重要的。那麽我們讓切入正題吧。

  (1)inline放在自定義函數前

   不要問為什麽,加就行了!額,這個東西好像可以讓你的函數有機會被計算機執行得稍微快一點,一般放在使用次數比較多的函數前,像check(),為sort()定制的CMP()等等,當然主函數前就不要放了。。。比如下面這個例子: 

1 inline bool CMP(const int &a,const
int &b){ 2 return a>b; 3 }

  (2)register放在變量前

     這個可以有機會把變量申請存儲在寄存器中,一般可以用來定義賦值次數較多的循環變量跑得飛快!

  (3)++i比i++快

     記住就行了,盡量用++i而不用i++,當然有特殊需要要用i++時除外。

  (4)讀入優化(很重要!)

  這是針對整數的。先介紹一下原理:讀入一個數時把它當作字符讀比當作一個數讀快,或者說用getchar(),gets()一類讀比用scanf("%d",&x)要快。而讀入字符時本身就是這樣讀的,當然就不用優化了。不要問為什麽!一般會自定義一個read()函數來讀取,寫法有很多,這裏貼上最常見的寫法:

 1 inline int read()
 2 {
 3     int f=1,x=0;    //f表示符號,1為正,-1為負
 4     char ss=getchar();
 5     while(ss<0||ss>9){if(ss==-)f=-1;ss=getchar();}//跳過數字前的空格等字符
 7     while(ss>=0&&ss<=9){x=x*10+ss-0;ss=getchar();}//讀到下一位ss,就把已讀到的乘10,相當於全部進一位,為存ss留出空間
 9     return f*x;
10 }
11 //使用時直接x=read(),相當於scanf("%d",&x);                    

   使用讀入優化在數據規模較小時優勢並不明顯,但在數據規模很大,比如上百萬時,使用讀入優化會比不使用的讀取速度快上幾倍。

  (5)輸出優化

  既然有讀入優化,自然也有輸出優化。只是輸出優化應用機會很少(一般只輸出幾個數),只有在需要輸出的答案較多時才可能會用到。原理同讀入優化,把原本為整數的答案轉為字符(串)形式後輸出。例如輸出一個int型變量x,一般會寫:

1 printf("%d",x);

     而用輸出優化就是:

1 void put(int x)
2 {3      if(!x) return ;   
4      put(x/10);  
5      printf("%c",x%10);     //因為得從最高位到最低位輸出,所以采用遞歸實現
7 }
8       

  (6)使用位運算符<<與>>

  這兩個東西是C語言中的位運算符,什麽意思呢?不會的可以百度一下,簡單來說就是一個數在二進制狀態下向左(右)移幾位(超出的位數舍棄)後的值。比如1<<2,意思是把1的二進制左移2位後得到的值。我們知道1的二進制是1(2),左移2位,就是100(2),也就是4。那麽8>>1的值是多少呢?8=1000(2),右移一位就是100(2),也就是4。也許你會驚奇地發現a<<b就等於a*2^b,a>>b就等於a/2^b。沒錯!這就是我們要用到它的地方。當你寫a=a/2時,你也可以寫成a=a>>1;a=a*2也可以寫成a=a<<1,等等。    

   那麽,為什麽我們非要用這個位運算符呢?因為在C語言中,位運算比起加減乘除等屬於較底層的操作,加減乘除其實也是通過位運算實現的,算是一種把底層操作更高級地“打包”起來,就像高級語言是由機器語言轉化而來的,執行時仍然要編譯為機器語言,這中間當然會花費一些不必要的時間和空間,因此越底層的操作往往越快。並且,我們可以用1<<n很方便地表示2^n,在實際操作中很有用處。

   

  初次發表博文,希望能幫到大家,如有錯誤,敬請指正!

2018-08-15

做OI題時的一些常用的常數優化小技巧