1. 双倍经验:https://www.lintcode.com/problem/count-of-smaller-number-before-itself/description?_from=ladder&&fromId=26
  2. 建议先把这道题做完之后再来做此题;
  3. 思路:相信看到题目的你第一时间想到的应该是冒泡排序,但是如果冒泡排序的话n <= 1e5 时间复杂度是O(n^2),这必然会TLE,并且冒泡排序并不能保证移动次数最小。
  4. 我们知道最终从低到高排列,而交换的都是不满足前小后大这一规律,所以我们很容易想到逆序对(i < j && A[i] > A[j])。
  5. 如果能想到逆序对,那么就已经做对一半了。
  6. 小朋友最小交换次数就是该小朋友在(正反逆序对(反:它前面有多少个数大于它; 正:它后面有多少个数小于它))中出现的次数总和,而交换 k 次不高兴程度就增加 k,所以最后每个小朋友的不高兴程度就是 1 k 的累加和。这样只要能统计处该小朋友在所有逆序对
  7. 比如样例(3 2 1
  8. 反逆序对:012
  9. 正逆序对:210
  10. 和:222
  11. 最终对每个小朋友的k进行单独的1k累加就是答案:9
  12. 最后利用高斯算法求每个小朋友逆序对个数的累加和
  13. #include "cstdio"
  14. #include "cstdlib"
  15. #include "iostream"
  16. #include "cstring"
  17. #include "cmath"
  18. #include "algorithm"
  19. #include "queue"
  20. #include "map"
  21. #include "vector"
  22. #include "stack"
  23. #include "set"
  24. #include "climits"
  25. using namespace std;
  26. typedef long long ll;
  27. typedef unsigned long long LL;
  28. const int inf = 0x3f3f3f3f;
  29. const int maxn = 1000010;
  30. inline int read() {
  31. char c = getchar(); int x = 0, f = 1;
  32. while(c < '0' || c > '9') {
  33. if(c == '-') f = -1;
  34. c = getchar();
  35. }
  36. while(c >= '0' && c <= '9') {
  37. x = x * 10 + c - '0';
  38. c = getchar();
  39. }
  40. return x * f;
  41. }
  42. //tree:结点数组,A:每个小朋友的身高,B:逆序对总数
  43. int tree[maxn], A[maxn], B[maxn], n;
  44. int lowbit(int x) {
  45. return x & -x;
  46. }
  47. void update(int x, int val) {
  48. while(x < maxn) {
  49. tree[x] += val;
  50. x += lowbit(x);
  51. }
  52. }
  53. int query(int x) {
  54. int ans = 0;
  55. while(x) {
  56. ans += tree[x];
  57. x -= lowbit(x);
  58. }
  59. return ans;
  60. }
  61. int main() {
  62. n = read();
  63. for(int i = 0; i < n; ++i) {
  64. A[i] = read() + 1;
  65. B[i] = query(A[i]); //求当前小朋友前面有多少个比自己高的小朋友
  66. //区间更新,根据差分update(L, val), update(R + 1, -val)
  67. //得到L = 1, R = A[i],这里的R本来要 + 1,但是因为我们要更新的是1-A[i] - 1的区间,所以这里R = A[i] - 1 + 1 = A[i]
  68. update(1, 1);
  69. update(A[i], -1);
  70. }
  71. memset(tree, 0, sizeof tree); //初始化用过一次的tree
  72. for(int i = n - 1; i >= 0; --i) {
  73. B[i] += query(A[i]); //求当前小朋友后面有多少个比自己矮的小朋友
  74. update(A[i] + 1, 1); //这里就不需要R了,只需要L = A[i] + 1即可,不明白的话自己手动模拟一遍就知道了
  75. }
  76. ll res = 0;
  77. for(int i = 0; i < n; ++i) res += (ll)(B[i] + 1) * B[i] / 2; //高斯算法求 1~B[i] 的累加和
  78. printf("%lld\n", res);
  79. return 0;
  80. }
点赞(0)
 

9.9 分

5 人评分

 

C语言网提供由在职研发工程师或ACM蓝桥杯竞赛优秀选手录制的视频教程,并配有习题和答疑,点击了解:

一点编程也不会写的:零基础C语言学练课程

解决困扰你多年的C语言疑难杂症特性的C语言进阶课程

从零到写出一个爬虫的Python编程课程

只会语法写不出代码?手把手带你写100个编程真题的编程百练课程

信息学奥赛或C++选手的 必学C++课程

蓝桥杯ACM、信息学奥赛的必学课程:算法竞赛课入门课程

手把手讲解近五年真题的蓝桥杯辅导课程

评论列表 共有 2 条评论

zjh 3年前 回复TA
@tym777 树状数组,学一下就知道了
tym777 3年前 回复TA
int lowbit(int x) {
    return x & -x;
}
这段的作用是什么啊?