差分、前綴和


差分

區間加:把數組a[l]到a[r]都加上k,這種操作稱為區間加。

如果一般朴素的想法應該是下面這樣的:

    int a[10005],l,r,k;
    for(int i=l;i<=r;i++){
        a[i]+=k;
    } 

但可以發現如果是l-r非常大的話,這個操作執行的次數又很多,那時間復雜度會很高(其實是我不會算)

所以我們通過引入差分的概念,簡化這個問題。

差分:差分即相鄰兩個數的差。我們用一個數組p存儲a的差分,那么p是a的差分數組,即pi=ai-ai-1  。

這張圖可以幫助更好地理解差分的概念

那么通過差分,如果繼續做區間加操作的話,只需要像下面這樣。

首先是查分數組的初始化:

    int p[10],a[10]={0,1,2,3,90,5,6,7,8,9};
        //p是a的差分數組 
    for(int i=1;i<=9;i++){
        p[i]=a[i]-a[i-1];
        cout<<p[i]<<" ";
    }

這段代碼會輸出

輸出: 1 1 1 87 -85 1 1 1 1 

那么我們現在就可以進行區間加操作了,代碼如下:

int p[10],a[10]={0,1,2,3,90,5,6,7,8,9};
void pl(int l,int r,int k){
    //操作:在[l,r]上加 k
    p[l]+=k,p[r+1]-=k;
        //注意是 r+1 !!! 
    return; 
}

那么當我們要輸出數組a的某一個元素要怎么辦呢

很簡單,通過差分數組p和原來的數組a“倒推”出a[i],代碼實現如下

void get_a(){
    for(int i=1;i<=9;i++){
        a[i]=p[i]+a[i-1];
    }
}

前綴和

前綴和其實就是用一個數組s來記錄數組a前i項的和,有點類似數列的求和。也可用來求區間和,如求數組a在區間[l,r]的和,就可以s[r]-s[l-1](注意要減1哦!!!!!)

我們在輸入a數組時可以預處理一下,代碼如下。

    int a[11],s[11];
    a[0]=0,s[0]=a[0];
    
    for(int i=1;i<=10;i++){
        a[i]=i*i;
        s[i]=s[i-1]+a[i];
        cout<<a[i]<<" ";
    }
    cout<<endl;
    for(int i=1;i<=10;i++){
        cout<<s[i]<<" ";
    }
    cout<<endl;

輸出結果如下:

1 4 9  16 25 36 49  64  81  100 
1 5 14 30 55 91 140 204 285 385 

那么區間[l,r]的和就是下面這樣:

int qjh(int l,int r){
    return s[r]-s[l-1];
}

cout<<qjh(3,6);

這里會輸出

86

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM