You are given an integer sequence of length N, a= {a1,a2,…,aN}, and an integer K.
a has N(N+1)⁄2 non-empty contiguous subsequences, {al,al+1,…,ar} (1≤l≤r≤N). Among them, how many have an arithmetic mean that is greater than or equal to K?
Constraints- All input values are integers.
- 1≤N≤2×105
- 1≤K≤109
- 1≤ai≤109
Input is given from Standard Input in the following format:
N K a1 a2 : aNOutput
Print the number of the non-empty contiguous subsequences with an arithmetic mean that is greater than or equal to K.
Sample Input 13 6 7 5 7Sample Output 1
5
All the non-empty contiguous subsequences of a are listed below:
- {a1} = {7}
- {a1,a2} = {7,5}
- {a1,a2,a3} = {7,5,7}
- {a2} = {5}
- {a2,a3} = {5,7}
- {a3} = {7}
Their means are 7, 6, 19⁄3, 5, 6 and 7, respectively, and five among them are 6or greater. Note that {a1} and {a3} are indistinguishable by the values of their elements, but we count them individually.
Sample Input 21 2 1Sample Output 2
0Sample Input 3
7 26 10 20 30 40 30 20 10Sample Output 3
13
题意:给n个数字,现在求 平均数大于K的集合(非空),有多少个?
思路:枚举所有的区间 ( L,R 】 (左开右闭,为了使区间不重叠,不同时包含端点) 我们先计算出sum[ i ]数组,代表前i个数的和,那么(L,R 】区间的和为sum【R】-sum【L】,sum【R】-sum【L】>=k*(R-L);==>sum【R】- sum【L】>=K*R-K*L;==>sum【R】-K*R>=sum【L】-K*L;(0<=L<R<=n)(L等于0时,第一个数字才能包含在区间里)(在符合此式子即为满足题意的区间) sum【R】-K*R (0<=R<=n)可以看成一个整体,先预处理求出所有该式子的值,这里我用num【i】代表sum【i】-K*i,确定区间右端点R,寻找有多少个左端点L 符合 num【L】<=num【R】,这个用树状数组来解决该问题(求R前面有多少个num【L】小于他的num)。因为num【i】很大,所以先离散化,然后用树状数组nlogn处理。
(因为(0,R],才能表示从a[1]开始的数据,所以num[0],sum[0]也是有必要算上的)
代码:
#include <iostream>
#include<stdio.h>
#include<string.h>
#include<math.h>
#include<queue>
#include<algorithm>
#define N 200500
#define LL long long
#define mem(a,b) memset(a,b,sizeof(a));
using namespace std;
LL sum[N],t[N];
LL tree[N];
int n,k,a,m,nn;
void add(int x)
{
while(x<=nn)//nn为上限,要大于离散化后的最大的数字,
{
tree[x]++;
x+=x&-x;//向上更新,树状数组核心代码。此处就不解释了,不会的先学树状数组。
}
}
LL query(int x)
{
LL num=0;
while(x)
{
num+=tree[x];
x-=x&-x;//向下求和
}
return num;
}
int main()
{
mem(t,0);
mem(tree,0);
mem(sum,0);
scanf("%d%d",&n,&k);
nn=n+10;
for(int i=1; i<=n; i++)
{
scanf("%d",&a);
t[i]=sum[i]=sum[i-1]+a-k;//预处理出sum[i]数组(就是上面讲解的num数组)
}//t[i]数组为离散化的辅助数组
sort(t,t+n+1);//排序,排n+1个数字的序(包括了sum[0])
m=unique(t,t+n+1)-t;//去重
for(int i=0; i<=n; i++)
sum[i]=lower_bound(t,t+m+1,sum[i])-t+1;//离散化
LL ans=0;
for(int i=0;i<=n;i++)
{
ans+=query(sum[i]);//查询有多少个小于sum[i]的数字
add(sum[i]);//更新树桩数组。
}
printf("%lld\n",ans);
}