介紹:
差分數組:
題目:
HDU 1556 Color the ball
題意:
給出一個區間n, n個數初始值都是0, 給出n個區間修改,修改是在[l,r]上加1, 最后輸出n個數。
分析:
屬於離線查詢, 可以維護差分數組來求出最后的數字。
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define INF 0x3f3f3f3f 4 const int N = 100000 + 10; 5 int m, q; 6 long long a[N], d[N], sum[N]; 7 int main() { 8 int n; 9 while (scanf("%d", &n) && n) { 10 memset(a, 0, sizeof(a));//初始化都為0 11 int l, r; 12 memset(d, 0, sizeof(d)); 13 d[1] = a[1];//特殊處理第一個數 14 for (int i = 0; i < n; i++) { 15 scanf("%d%d", &l, &r); 16 d[l] += 1; 17 d[r+1] -= 1; 18 } 19 memset(sum, 0, sizeof(sum)); 20 for (int i = 1; i <= n; ++i) { 21 sum[i] = sum[i-1] + d[i]; //求d[i]前綴和, 也就是修改后的a[i] 22 } 23 for (int i = 1; i <= n; ++i){ 24 printf("%lld",sum[i]); 25 if(i != n) printf(" "); 26 } 27 puts(""); 28 } 29 30 return 0; 31 }
BZOJ 3043 IncDec Sequence
題意:
給定一個長度為n的數列a[i],每次可以選擇一個區間[l,r],使這個區間內的數都加一或者都減一。
求:(1)至少需要多少次操作才能使數列中的所有數都一樣。
(2)在保證最少次數的前提下,最終得到的數列有多少種
分析:
因為我們最終是求一個所有數的一樣的序列, 所以其差分數組就是除了d[1]外,d[2]~d[n]全為0。
然后題目中區間加一或者區間減一操作, 其實就是在差分數組中, 找出兩個下標i, j, d[i]++, d[j]--(或者d[i]--, d[j]++)
所以我們就可以利用這個操作把d[2]~d[n]中的正數和負數中和, 然后還有會一部分正數(或負數)多出來, 我們只需要在這個點上面直接加減就好(這個單點操作其實有兩重意義,涉及第二問)
我們求出d[2]~d[n]的正數和絕對值pos, 負數和絕對值neg
所以第一問的答案就是max(pos,neg)
剛剛提到了有一個單點操作的意義, 我們就拿d[i]++來說吧
第一種含義是, 因為d[1]是什么並沒有關系, 所以可以代表d[1]-- , d[i]++, 實際意義就是數組a[1]~a[i-1]都減去1。
第二種含義是, 因為修改區間[l,r]加一是在d[l]++, d[r+1]--, 如果這個r等於n的時候, 那么r+1並沒有意義, 所以也成了單點操作, 實際意義就是a[i]~a[n]加上1。
就是說那個多出來的d[i]可以配給d[1]或者d[n+1](沒有意義)
所以我們的問題二可以轉化為d[1]的取值個數, 那么可以配0次, 1次...到abs(pos-neg)次, 所以最終d[1]的取值總共abs(pos-neg) + 1次。