题意:
给出一个长度为 n (<=100000) 的序列,有q次操作,每次操作将最大的K个数取出来求和,然后将这K个数减1,再放回序列,求最后的答案。
题解:
不难想首先将序列从小到大排序,从最后取出K个数,然后区间求和,区间减1,可以发现很容易保证这个序列的单调性。
比如n = 6 K = 2 序列为 1 2 3 4 4 5 那么就应该修改成这样 1 2 3 3 4 4,那么就应该找出K个数中最小的那个数的前驱后继。
代码:
#include <bits/stdc++.h> using namespace std; #define LL long long const int N = 1e5 + 7; LL sum[N << 2], lz[N << 2], ans, mif[N << 2]; int n, ai[N], K, q; #define mid (l + r >> 1) #define lson o << 1, l, mid #define rson o << 1 | 1, mid + 1, r void build (int o, int l, int r) { if (l == r) { sum[o] = ai[l]; return; } build(lson); build(rson); sum[o] = sum[o << 1] + sum[o << 1 | 1]; } void pushdown (int o, int l, int r) { sum[o << 1] += (mid - l + 1) * lz[o]; mif[o << 1] += (mid - l + 1) * lz[o]; lz[o << 1] += lz[o]; sum[o << 1 | 1] += (r - mid) * lz[o]; mif[o << 1 | 1] += (r - mid) * lz[o]; lz[o << 1 | 1] += lz[o]; lz[o] = 0; } void update (int o, int l, int r, int L, int R, int x) { if (l == L && r == R) { lz[o] += x; mif[o] += (R - L + 1) * x; sum[o] += (R - L + 1) * x; return; } pushdown(o, l, r); if (R <= mid) update(lson, L, R, x); else if (L > mid) update(rson, L, R, x); else update(lson, L, mid, x), update(rson, mid + 1, R, x); sum[o] = sum[o << 1] + sum[o << 1 | 1]; mif[o] = mif[o << 1] + mif[o << 1 | 1]; } LL query (int o, int l, int r, int L, int R) { if (l == L && r == R) return sum[o]; pushdown(o, l, r); if (R <= mid) return query (lson, L, R); else if (L > mid) return query (rson, L, R); else return query (lson, L, mid) + query (rson, mid + 1, R); } int lazy (int o, int l, int r, int x) { if (l == r && l == x) return mif[o]; pushdown (o, l, r); if (x <= mid) return lazy (lson, x); else if (x > mid) return lazy (rson, x); } int find (int x) { int l = 1, r = n; while (l < r) { if (ai[mid] + lazy(1, 1, n, mid) >= x) r = mid; else l = mid + 1; } return l; } int main () { scanf ("%d", &n); for (int i = 1; i <= n; ++i) scanf ("%d", &ai[i]); sort (ai + 1, ai + 1 + n); build (1, 1, n); scanf ("%d", &q); while (q--) { scanf ("%d", &K); int w = ai[n - K + 1] + lazy(1, 1, n, n - K + 1); int x = find (w), y = find (w + 1); if (ai[x] + lazy(1, 1, n, x) != ai[y] + lazy(1, 1, n, y)) { ans += query (1, 1, n, x, x + K - n + y - 2); ans += query (1, 1, n, y, n); update (1, 1, n, x, x + K - n + y - 2, -1); update (1, 1, n, y, n, -1); } else { ans += query (1, 1, n, x, x + K - 1); update (1, 1, n, x, x + K - 1, -1); } } cout << ans << endl; return 0; }
总结:
善于观察因为只减1,很容易就保证了序列的单调性呀~