[Luogu]P2717 寒假作业

Description

\(Link\)

Solution

我们把原序列都减掉\(k\),然后问题就转化为求有多少个连续子序列的和大于等于\(0\)

求出新序列\(\{b_i\}\)的前缀和\(\{s_i\}\),那么即求有多少对\((i,j)(i\le{j})\)满足\(s[j]-s[i-1]\ge{0}\)。即\(s[j]\ge{s[i-1]}\)

\(i\le{j}\),所以\(i-1<j\),问题转化为求顺序对的个数。

然后要注意\(i-1\)可能取到\(0\),所以之前要单独统计一遍\(\forall{i},s[i]\ge{0}\)。(思想:因为\(s[0]\)不好统计,所以把它单独拿出来算,又\(s[0]=0\),所以直接算\(\ge{0}\)个数)。因为是\(i-1<j\),所以要先\(ask\)\(add\)

Code

#include <bits/stdc++.h>

using namespace std;

#define lowbit(x) ((x) & (-x))
#define ll long long

int n, k, a[200005], c[200005];

ll res, sum[200005], p[200005], r[200005];

int read()
{
	int x = 0, fl = 1; char ch = getchar();
	while (ch < '0' || ch > '9') { if (ch == '-') fl = -1; ch = getchar();}
	while (ch >= '0' && ch <= '9') {x = (x << 1) + (x << 3) + ch - '0'; ch = getchar();}
	return x * fl;
}

void add(int x, ll d)
{
	while (x <= n)
	{
		c[x] += d;
		x += lowbit(x);
	}
	return;
}

int ask(int x)
{
	int s = 0;
	while (x)
	{
		s += c[x];
		x -= lowbit(x);
	}
	return s;
}

int main()
{
//	freopen("3.in", "r", stdin);
	n = read(), k = read();
	for (int i = 1; i <= n; i ++ )
	{
		a[i] = read();
		sum[i] = sum[i - 1] + (ll)(a[i]);
		r[i] = sum[i] - 1ll * i * k;
		p[i] = sum[i] - 1ll * i * k;
		res += (r[i] >= 0);
	}
	sort(p + 1, p + n + 1);
	int t = unique(p + 1, p + n + 1) - p - 1;
	for (int i = 1; i <= n; i ++ )
		r[i] = lower_bound(p + 1, p + t + 1, r[i]) - p;
	for (int i = 1; i <= n; i ++ )
	{
		res += ask(r[i]);
		add(r[i], 1);
	}
	printf("%lld\n", res);
	return 0;
}
posted @ 2020-10-21 12:58  andysj  阅读(59)  评论(0编辑  收藏  举报