题解 P2717 【寒假作业】
非常简单的cdq分治
先把所有数-=k,转化为平均数>=0的区间数量
也就是区间和>=0的区间数量
对于区间[l, r]内部所有区间的贡献,令区间中点为mid,先计算[l, mid]和[mid + 1, r]的所有贡献,然后再计算[l, r]内所有跨过区间中点mid的区间贡献就行
跨过中点的区间一定是
有前缀和转化为逆序对的做法,实质其实一样,都是cdq分治
#include <cstdio>
#include <algorithm>
using namespace std;
int n, k, a[100010];
int tmp[100010];
long long cdq(int l, int r)
{
if (l == r) return a[l] >= 0;
int mid = (l + r) / 2;
long long ans = cdq(l, mid) + cdq(mid + 1, r);
tmp[mid] = a[mid];
tmp[mid + 1] = a[mid + 1];
for (int i = mid - 1; i >= l; i--)
tmp[i] = tmp[i + 1] + a[i];
for (int i = mid + 2; i <= r; i++)
tmp[i] = tmp[i - 1] + a[i];
sort(tmp + l, tmp + mid + 1);
sort(tmp + mid + 1, tmp + r + 1);
for (int i = l, j = r; i <= mid; i++)
{
while (j > mid && tmp[i] + tmp[j] >= 0) j--;
ans += r - j;
}
return ans;
}
int main()
{
scanf("%d%d", &n, &k);
for (int i = 1; i <= n; i++) scanf("%d", &a[i]), a[i] -= k;
printf("%lld\n", cdq(1, n));
return 0;
}