前缀和求区间

题意:求x是区间第K小数的区间个数,就是找有k-1个数小于X的区间。
我们可以把小于等于x的值的位置由1代替,而大于x的值的位置为0.这样就变成一个 01 序列。

  • 1 :小于等于x
  • 0 : 大于x

我们设 a[] 为一个前缀和数组,那么我们只需要找到 (区间里1的数量 == k && 该区间包含x) 前面我们定义 1 的意义为小于等于x ,所以在我们这里需要找区间含1数量为k

	这里我们可以想到一个比较直接的方法,找到满足的区间----O(n^2) 
    
    pos: x值的位置
    
	for(int i = 1; i<= pos ;i++ ){//枚举pos左侧
    
    	for(int j = pos;j<= n;j++){//枚举pos右侧
        	if( a[j] -a[i-1] == k) ans++;
        }
    }

显然,我们需要复杂度更低的方法

设 b[] 为 a[i] 对应的数量
后面就具体看代码

#include<bits/stdc++.h>
#define ms(__x__,__val__) memset(__x__, __val__, sizeof(__x__))
using namespace std;
int main()
{
 	ios::sync_with_stdio(0);cin.tie(0); cout.tie(0);
 	
	int n,x,k;
	cin>>n>>x>>k;
	
	int a[n+2];
	ms(a,0);
	int pos = 0;
	for(int i = 1;i <= n ; i++){
		int w;
		cin>>w;
		if( w == x ) pos = i;
		a[i] = a[i-1] + (w <= x); //获得a[]数组
	}
	
	int ans = 0;
	
/*	
(O(n^2))
	for(int i = 1;i<=pos ;i++){
		for(int j = pos;j<=n;j++){
			if(a[j] - a[i-1] == k) ans++;
		}
	}
*/	
	int b[2000005];
	ms(b,0);
	
	for(int i = pos ;i<=n;i++){
		b[a[i]]++;	             //只需要得到pos右边对应a[i]的数量
	}
	
	for(int i=1; i<=pos; i++){
		ans += b[a[i-1] + k];       // a[i-1] + k == a[]所对应的值,b[]存的就是对应a[]值的数量
	}

	
	cout<<ans<<endl;

}



很久之前做的题目,我看题解好像没写这种就写了一下,第一次写题解。