每个小朋友都有一个不高兴的程度。开始的时候,所有小朋友的不高兴程度都是0。
如果某个小朋友第一次被要求交换,则他的不高兴程度增加1,如果第二次要求他交换,则他的不高兴程度增加2(即不高兴程度为3),依次类推。当要求某个小朋友第k次交换时,他的不高兴程度增加k。
请问,要让所有小朋友按从低到高排队,他们的不高兴程度之和最小是多少。
如果有两个小朋友身高一样,则他们谁站在谁前面是没有关系的。
第二行包含$n$个整数 $H_1$ $H_2$ … $H_n$,分别表示每个小朋友的身高。
3 2 1
对于30%的数据, $1 \le n \le 1000$;
对于50%的数据, $1 \le n \le 10000$;
对于100%的数据,$1 \le n \le 100000$,$0 \le Hi \le 1000000$。
![](https://i-blog.csdnimg.cn/blog_migrate/ae336e1d77ea88131ae61225b39f0395.png)
在这个题目中,需要做的是,
(1)自左向右把序列添加到树状数组中。注意,添加到树状数组中的不是序列的值,而是把序列值当作插入树状数组时的下标,插入的值为1。比如,在处理$a[i]$之前,$a[1]$~$a[i - 1]$已经处理完了。如果$a[j]$<$a[i]$($1 \le j<i$),在树状数组的下标中$a[j]$必定出现在$a[i]$的前面,所以,只要统计$[1, i - 1]$区间内比$a[i]$小或者等于的数字个数,就可以知道$[1, i - 1]$区间内比$a[i]$小的数字个数了。因为这里统计涉及到求前缀和,所以这就是为什么用树状数组的原因。
(2)自右向左把序列添加到树状数组中。这样可以统计出$a[i]$右边比$a[i]$小的元素的个数。注意,统计比$a[i]$小的元素的个数,是计算$sum(a[i] - 1)$,而不是$sum(a[i])$,因为$a[i]$右边有可能有等于$a[i]$的数字存在。(其中,$sum(x)$表示树状数组中的$[1, x]$区间的前缀和)。
还有两点需要注意:①这个题目中数值$0 \le a[i] \le 10^6$,而在树状数组中$0$是不能作为下标的。所以,在输入序列$a[i]$时,应把$a[i]$加一个正偏移量;②树状数组的最大长度是$max\{a_1, a_2, a_3, ……, a_n\} + 偏移量$,而不是$N$。
#include<bits/stdc++.h> using namespace std; #define MAXV 1000010 #define MAXN 100010 typedef long long LL; LL n, a[MAXN], cnt[MAXN], bits[MAXV], maxv; template<class T> inline void read(T& x) { char t; bool sign = false; while((t = getchar()) != '-' && (t < '0' || t > '9')); if(t == '-')sign = true, t = getchar(); x = t - '0'; while((t = getchar()) >= '0' && t <= '9')x = x * 10 + t - '0'; if(sign)x = -x; } LL sum(int x) { LL res = 0; for(int i = x; i > 0; i -= i & -i)res += bits[i]; return res; } void add(LL x, LL val) { for(; x <= maxv; x += x & -x)bits[x] += val; } int main() { #ifndef ONLINE_JUDGE freopen("input.txt", "r", stdin); #endif // ONLINE_JUDGE while(~scanf("%I64d", &n)) { memset(cnt, 0, sizeof(cnt)); maxv = 0; for(int i = 1; i <= n; ++i) { read(a[i]); ++a[i]; if(a[i] > maxv)maxv = a[i]; } memset(bits, 0, sizeof(bits)); for(int i = 1; i <= n; ++i) { cnt[i] += (i - 1) - sum(a[i]); add(a[i], 1); } memset(bits, 0, sizeof(bits)); for(int i = n; i > 0; --i) { cnt[i] += sum(a[i] - 1); add(a[i], 1); } LL ans = 0; for(int i = 1; i <= n; ++i)ans += (1LL + cnt[i]) * cnt[i] / 2LL; printf("%I64d\n", ans); } return 0; }
#include<bits/stdc++.h> using namespace std; #define MAXN 100010 typedef long long LL; LL n; struct Node { LL order, val, cnt; } nodes[MAXN], tmp[MAXN]; template <class T> inline void read(T &x) { int t; bool flag = false; while((t = getchar()) != '-' && (t < '0' || t > '9')) ; if(t == '-') flag = true, t = getchar(); x = t - '0'; while((t = getchar()) >= '0' && t <= '9') x = x * 10 + t - '0'; if(flag) x = -x; } void merge_sort(int start, int end, bool dir) { int mid = (start + end) >> 1; if(end > start + 1) { //end - start + 1 > 2 merge_sort(start, mid, dir); merge_sort(mid + 1, end, dir); } if(dir) { int pl = start, pr = mid + 1; for(int i = start; pl <= mid || pr <= end; ++i) { if(pl > mid)tmp[i] = nodes[pr++]; else if(pr > end)tmp[i] = nodes[pl++]; else if(nodes[pl].val <= nodes[pr].val)tmp[i] = nodes[pl++]; else if(nodes[pl].val > nodes[pr].val) { nodes[pr].cnt += mid - pl + 1; tmp[i] = nodes[pr++]; } } } else { int pl = mid, pr = end; for(int i = end; pl >= start || pr >= mid + 1; --i) { if(pr < mid + 1)tmp[i] = nodes[pl--]; else if(pl < start)tmp[i] = nodes[pr--]; else if(nodes[pr].val >= nodes[pl].val)tmp[i] = nodes[pr--]; else if(nodes[pr].val < nodes[pl].val) { nodes[pl].cnt += pr - mid; tmp[i] = nodes[pl--]; } } } memcpy(nodes + start, tmp + start, sizeof(nodes[start]) * (end - start + 1)); } bool cmp(Node& n1, Node& n2) { return n1.order < n2.order; } int main() { #ifndef ONLINE_JUDGE freopen("input.txt", "r", stdin); #endif // ONLINE_JUDGE while(~scanf("%I64d", &n)) { memset(nodes, 0, sizeof(nodes)); for(int i = 1; i <= n; ++i)read(nodes[i].val), nodes[i].order = i; merge_sort(1, n, true); sort(nodes + 1, nodes + n + 1, cmp); merge_sort(1, n, false); LL ans = 0; for(int i = 1; i <= n; ++i)ans += (1LL + nodes[i].cnt) * nodes[i].cnt / 2LL; printf("%I64d\n", ans); } return 0; }
#include<bits/stdc++.h> using namespace std; #define MAXV 1000010 #define MAXN 100010 typedef long long LL; LL n, a[MAXN], b[MAXN], buf[MAXN], cnt[MAXN]; template<class T> inline void read(T& x) { char t; bool sign = false; while((t = getchar()) != '-' && (t < '0' || t > '9')); if(t == '-')sign = true, t = getchar(); x = t - '0'; while((t = getchar()) >= '0' && t <= '9')x = x * 10 + t - '0'; if(sign)x = -x; } void discrete(LL* bef, LL* aft) { sort(buf + 1, buf + n + 1); int m = unique(buf + 1, buf + n + 1) - buf; for(int i = 1; i <= n; ++i)aft[i] = lower_bound(buf + 1, buf + m + 1, bef[i]) - buf; } typedef struct { int root[MAXN], ncnt; struct seg { int lch, rch, cnt; } segs[MAXN * 20]; void clear() { memset(segs, 0, sizeof(segs)); memset(root, 0, sizeof(root)); ncnt = 0; } void update(int& croot, int proot, int val, int l, int r) { if(croot == 0) { croot = ++ncnt; segs[croot].cnt = segs[proot].cnt + 1; } if(l == r)return; int mid = (l + r) >> 1; if(val <= mid) { segs[croot].rch = segs[proot].rch; update(segs[croot].lch, segs[proot].lch, val, l, mid); } else { segs[croot].lch = segs[proot].lch; update(segs[croot].rch, segs[proot].rch, val, mid + 1, r); } } int query(int qlr, int qrr, int k, int l, int r) { if(l == r)return l; int mid = (l + r) >> 1; if(k <= segs[segs[qrr].lch].cnt - segs[segs[qlr].lch].cnt) { return query(segs[qlr].lch, segs[qrr].lch, k, l, mid); } else { return query(segs[qlr].rch, segs[qrr].rch, k - (segs[segs[qrr].lch].cnt - segs[segs[qlr].lch].cnt), mid + 1, r); } } } PerSegTree; PerSegTree pst; int main() { #ifndef ONLINE_JUDGE freopen("input.txt", "r", stdin); #endif // ONLINE_JUDGE while(~scanf("%I64d", &n)) { pst.clear(); memset(cnt, 0, sizeof(cnt)); for(int i = 1; i <= n; ++i)read(a[i]), buf[i] = a[i]; discrete(a, b); for(int i = 1; i <= n; ++i)pst.update(pst.root[i], pst.root[i - 1], int(b[i]), 1, n); for(int i = 2; i <= n; ++i){ int low = 0, high = i, mid, num; while(low < high - 1){ mid = (low + high) >> 1; num = pst.query(pst.root[0], pst.root[i - 1], mid, 1, n); if(num <= b[i])low = mid; else high = mid; } cnt[i] += i - 1 - low; } for(int i = 1; i < n; ++i){ int low = 0, high = n - i + 1, mid, num; while(low < high - 1){ mid = (low + high) >> 1; num = pst.query(pst.root[i], pst.root[n], mid, 1, n); if(num < b[i])low = mid; else high = mid; } cnt[i] += low; } // for(int i = 1; i <= n; ++i)printf("%I64d ", cnt[i]); printf("\n"); LL ans = 0; for(int i = 1; i <= n; ++i)ans += (1LL + cnt[i]) * cnt[i] / 2LL; printf("%I64d\n", ans); } return 0; }