競技プログラミング講習/計算量 
         
        
          概要 
          
            今回は、競技プログラミングにおいて知っておくと便利な計算量ついて解説します。 
         
        
          
            
              重要語
             
            
              時間計算量
             
            
              プログラムがどれくらいの時間で終わるかの指標
             
            
              空間計算量
             
            
              プログラムがどれくらいのメモリを使用するかの指標
             
          
          
            
              必要語
             
            
              今回の必要語はありません。
             
          
         
        
          オーダー記法 
          
            コンピュータが計算をするときには僅かですが時間がかかるので、計算回数が多くなると実行時間が長くなります。2 回計算するといったようなことです。2 +N+3と求めることは大変です。
              係数を無視する(ただし定数は1とする)。 
              Nを大きくしていったときに最も影響の強い項以外無視する。 
             
            例えば2N2 +N+3であれば、
            
              係数を無視して、N2 +N+1とする。 
              N2 ,N,1のうちN2 が最も影響が強い。 
             
            よって、O(N2 )と表すことができます。
           
         
        
          時間計算量 
          
            プログラムには時間がかかります。その時間の見積もりは重要です。
           
         
        
          
            
計算量の例 
            
              例えばNが入力として与えられて、1+2+3+...+Nを求めろという問題に対して、以下のような回答が考えられます。
             
          
         
        
          
            
              
                COPY 
               
            
            
            
#include  < bits/ stdc++ .h> 
using  namespace  std; 
int  main()  { 
    int  n; 
    cin >>  n; 
    int  ans =  0 ; 
    for  ( int  i =  1 ;  i <=  n;  i++)  { 
        ans +=  i; 
    } 
    cout <<  ans <<  endl; 
    return  0 ; 
}  
            
           
         
        
          
            
              しかし、これには足し算をN回繰り返す必要があり、時間計算量はO(N)です。一方、こちらのプログラムはどうでしょう。
             
          
         
        
          
            
              
                COPY 
               
            
            
            
#include  < bits/ stdc++ .h> 
using  namespace  std; 
int  main()  { 
    int  n; 
    cin >>  n; 
    int  ans =  n *  ( n +  1 )  /  2 ; 
    cout <<  ans <<  endl; 
    return  0 ; 
}  
            
           
         
        
          
            
              これは和の公式1+2+3+...+N=N(N+1)/2を用いて計算しています。こちらは四則演算を数回しているだけなので、O(1)です。 
          
         
        
          
            
TLE 
            
              AtCoderのジャッジではTLE(Time Limit Exceeded)というものがあります。これが出た場合は計算量を見積もってみましょう
              (TLEが出てから計算量を見積もってもいいですが、コードを書く前に見積もることをお勧めします)。8 回くらいの計算をすることができます。5 となっていたら、O(N2 )はTLEですが、O(N)であれば間に合います。5 であればO(1)もO(N)もどちらも間に合ってACをとることができます。
              ABCなどのコンテストにおいてTLEでなければ実行時間は順位に関係ないため、O(1)とO(N)の両方を思いついた場合は無理にO(1)を書かずに、書きやすい(もしくはバグらせにくい方)を書きましょう。
              しかし、1≦N≦109 であれば、O(N)はTLEになりますので、諦めてO(1)を書きましょう。 
          
         
        
          空間計算量 
          
            C++において、空間計算量を気にすることはあまりありませんが、int a[100000][100000]のような大きすぎる配列は確保できないということを知っておきましょう。
           
         
        
          
            
空間計算量の例 
            
              入力としてa,b,cが与えられ、a*b*cを出力します。
             
          
         
        
          
            
              
                COPY 
               
            
            
            
#include  < bits/ stdc++ .h> 
using  namespace  std; 
int  main()  { 
    int  a,  b,  c; 
    cin >>  a >>  b >>  c; 
    cout <<  a *  b *  c <<  endl; 
    return  0 ; 
}  
            
           
         
        
          
            
              この場合、どのような入力でも使う変数はa,b,cの3つなので、空間計算量はO(1)です。
             
          
         
        
          
            
              
                COPY 
               
            
            
            
#include  < bits/ stdc++ .h> 
using  namespace  std; 
typedef  long  long  ll; 
int  main()  { 
    int  n; 
    cin >>  n; 
    vector< int >  a( n); 
    for  ( int  i =  0 ;  i <  n;  i++)  { 
        cin >>  a[ i]; 
    } 
    ll ans =  1 ; 
    for  ( int  i =  0 ;  i <  n;  i++)  { 
        ans *=  a[ i]; 
    } 
    cout <<  ans <<  endl; 
    return  0 ; 
}  
            
           
         
        
          
            
              この場合、変数はn,ans,i,vector<int> a(n)を使っています。
              このうちvector<int> a(n)は入力Nに比例してメモリを消費するので、空間計算量はO(N)となります。typedef long long ll;はlong longという型名をllとして使えるようにする記述で、
              タイプ数が少なくなって便利であるため使用しています。
             
          
         
        
          
            
MLE 
            
              AtCoderのジャッジではMLE(Memory Limit Exceeded)というものがあります。これはC++においてなかなか起こりづらいですが、
              問題名の下に「メモリ制限」が書いてあり、メモリ使用量がこれを超えるとMLEと判定されます。9 Bですから、int型の配列であれば要素数は108 位が限度でしょう。 
          
         
        
          練習問題 
          
            理解できたか確認するために、練習問題を解いてもらいます。EX21 - 計算量の見積もり