Codeforces 1167F 计算贡献
题意:给你一个函数f,计算∑(i = 1 to n)(j = i to n) f(i, j)。f(i, j)的定义是:取出数组中i位置到j位置的所有元素,排好序,然后把排好序的位置 * 元素 加起来。比如[7, 4, 2, 1], f(1, 4)是1 * 1 + 2 * 2 + 3 * 4 + 5 * 7;
思路:(来自PinkRabbit)我们计算每一个每一个x出现了多少次,然后加起来就是答案。我们假设一个元素y < x, 并且在x的左边,那么y对x的贡献为pos(y) * (n - pos(x) + 1)(pos(x)是x的位置),即包含y和x的区间个数。右边同理。我们用树状数组来维护.
代码:
#include <bits/stdc++.h> #define LL long long #define ls(x) (x << 1) #define rs(x) ((x << 1) | 1) #define lowbit(x) (x & (-x)) using namespace std; const int maxn = 500010; const LL mod = 1000000007; LL a[maxn], p[maxn]; LL n; class BIT { public: LL tr[maxn]; void add(int x, LL y) { for (; x <= n; x += lowbit(x)) { tr[x] += y; tr[x] %= mod; } } LL ask(int x) { LL ans = 0; for (; x; x -= lowbit(x)) { ans += tr[x]; ans %= mod; } return ans; } }; BIT t1, t2; bool cmp(LL x, LL y) { return a[x] < a[y]; } int main() { scanf("%lld", &n); for (int i = 1; i <= n; i++) { scanf("%lld", &a[i]); p[i] = i; } LL ans = 0; sort(p + 1, p + 1 + n, cmp); for (int i = 1; i <= n; i++) { LL now = p[i]; ans = (ans + (a[now] * (((n - now + 1) * now) % mod)) % mod) % mod; ans = (ans + (a[now] * ((t1.ask(now) * (n - now + 1)) % mod + (t2.ask(n - now + 1) * now) % mod) % mod) % mod) % mod; t1.add(now, now); t2.add(n - now + 1, n - now + 1); } printf("%lld\n", ans); }