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);
}

  

猜你喜欢

转载自www.cnblogs.com/pkgunboat/p/10878337.html