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>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值