CF1005E

題意

n個數字,問m是多少個區間的中位數?偶數個數字的區間中位數認爲是中間靠左的那個數字,比如(1,3,7,8)中位數爲3。

E1:這n個數字是1~n的一個排列

E2:n個數字,數字大小不超過2e5


題解

做法①(可過E1,過不了E2):

思路請看:51Nod ~ 1682 ~ 中位數計數 (思維)

  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. const int MAXN = 2e5+5;
  4. const int FIX = 2e5;
  5. typedef long long LL;
  6. int n, m, a[MAXN], pos, b[MAXN*2];
  7. int main()
  8. {
  9. scanf(“%d%d”, &n, &m);
  10. for (int i = 0; i < n; i++)
  11. {
  12. scanf(“%d”, &a[i]);
  13. if (a[i] == m) pos = i;
  14. }
  15. int cnt = 0;
  16. LL ans = 0;
  17. for (int i = pos; i >= 0; i–)
  18. {
  19. if (a[i] > m) cnt++;
  20. if (a[i] < m) cnt–;
  21. b[FIX+cnt]++;
  22. }
  23. cnt = 0;
  24. for (int i = pos; i < n; i++)
  25. {
  26. if (a[i] > m) cnt++;
  27. if (a[i] < m) cnt–;
  28. ans += b[FIX-cnt];
  29. ans += b[FIX-cnt+1];
  30. }
  31. printf(“%lld\n”, ans);
  32. return 0;
  33. }
  34. /*
  35. 5 4
  36. 2 4 5 3 1
  37. */

做法②(E1,2均可過):

中位數小於等於m的區間 - 小於等於m-1的區間=中位數等於m的區間 ,現在我們需要搞一個計算中位數小於等於x的區間個數的函數。首先如果中位數小於等於x,那麼<=x的數字一定大於>x的數字,我們記<=x的爲+1,>x的數字記爲-1,我們用變量s記錄這個值,如果對於[L,R]區間(L<R),L位置時的s小於R位置時的s,證明[L,R]區間是一個符合要求的區間。

枚舉右端點,維護s變量,對於右端點 R,怎麼得到s_L <= s_R 的 L 的個數呢?


O(n)做法:

數組cnt[i]用於統計 s = i 的點的個數(由於s有負值所以我們以n作爲0點即可),add維護s_L <= s_i 的 L 的個數

如果當前元素a[i]<=x,s要++,那麼對於 i 位置符合要求的點比 i-1 多了cnt[++s]個

如果當前元素a[i]>x,s要–,那麼對於 i 位置符合要求的點比 i-1 少了cnt[s–]個

統計答案,每次ans+=add即可,最終ans就是中位數大於等於x的區間數。

  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. const int MAXN = 2e5+5;
  4. typedef long long LL;
  5. int n, m, a[MAXN], cnt[MAXN*2];
  6. LL slove(int x)
  7. {
  8. memset(cnt, 0, sizeof(cnt));
  9. int s = n; cnt[n] = 1;
  10. LL add = 0, ans = 0;
  11. for (int i = 0; i < n; i++)
  12. {
  13. if (a[i] <= x) add += cnt[++s];//add += cnt[++s]同s++; add += cnt[s];
  14. else add -= cnt[s--];//add -= cnt[s--]同add -= cnt[s]; s--;
  15. cnt[s]++;
  16. ans += add;
  17. }
  18. return ans;
  19. }
  20. int main()
  21. {
  22. scanf("%d%d", &n, &m);
  23. for (int i = 0; i < n; i++) scanf("%d", &a[i]);
  24. printf("%lld\n", slove(m) - slove(m-1));
  25. return 0;
  26. }
  27. /*
  28. 5 4
  29. 1 4 5 60 4
  30. */


O(n*logn)(BIT做法):

數組cnt[i]用於統計 s = i 的個數(由於s有負值所以我們以n作爲0點即可)

BIT維護cnt[s]這個數組,枚舉右端點,每次對於當前右端點,查詢有cnt中有多少個小於等於s的值。


  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. const int MAXN = 2e5+5;
  4. typedef long long LL;
  5. int n, m, a[MAXN];
  6. struct BIT
  7. {
  8. int n, c[MAXN*2];
  9. void init (int n)
  10. {
  11. this->n = n;
  12. memset(c, 0, sizeof(c));
  13. }
  14. void add(int p, int x)
  15. {
  16. for (int i = p; i <= n; i += i&-i)
  17. c[i] += x;
  18. }
  19. int sum(int p)
  20. {
  21. int ans = 0;
  22. for (int i = p; i >= 1; i -= i&-i)
  23. ans += c[i];
  24. return ans;
  25. }
  26. }bit;
  27. LL slove(int x)
  28. {
  29. bit.init(2*n+1);
  30. bit.add(n+1, 1);
  31. int s = n+1;
  32. LL ans = 0;
  33. for (int i = 1; i <= n; i++)
  34. {
  35. if (a[i] <= x) s++;
  36. else s--;
  37. bit.add(s, 1);
  38. ans += bit.sum(s);
  39. }
  40. return ans;
  41. }
  42. int main()
  43. {
  44. scanf("%d%d", &n, &m);
  45. for (int i = 1; i <= n; i++) scanf("%d", &a[i]);
  46. printf("%lld\n", slove(m) - slove(m-1));
  47. return 0;
  48. }
  49. /*
  50. 5 4
  51. 1 4 5 60 4
  52. */




            </div>
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章