题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5806
题意
给你一个数列,找出所有满足区间的第k大的数字大于m的区间数量
题解
用尺取法,复杂度为O(n)。从左往右扫描整个区间,用s保存从左向右扫描过程大于等于m的个数,st为左端点。当向右扫描过程中大于m的个数等于k个时,这时,通过左端点的值与m的大小来决定左端点是否右移。当小于时,可向右移动,通过下标计算可满足区间数目;否则不能。(反复进行循环,直至左端点对应的值大于等于m)。接着进行计算可满足区间数目,左端向右推进一,s自减一;接着进行。直至又端点进行至最后一位。
尺取法:
- 顾名思义,像尺子一样取一段,尺取法通常是对数组保存一对下标,即所选取的区间的左右端点,然后根据实际情况不
断地推进区间左右端点以得出答案。 - 之所以需要掌握这个技巧,是因为尺取法比直接暴力枚举区间效率高很多,尤其是数据量大的
时间复杂度
- 时间复杂度是同一问题可用不同算法解决,而一个算法的质量优劣将影响到算法乃至程序的效率。算法分析的目的在于
选择合适算法和改进算法。 - 时间复杂度常用大O符号表述。不包括这个函数的低阶项和首项系数。
——————————————————————————————————————————————
AC Code
#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <vector>
#include <string>
#include <map>
#include <set>
#include <stack>
#include <queue>
#include <functional>
#include <algorithm>
#define _USE_MATH_DEFINES
using namespace std;
typedef long long ll;
int a[200000+5];
int main()
{
int T;
cin>> T;
while(T--)
{
int n, m, k;
memset(a,0,sizeof(a));
scanf("%d %d %d",&n,&m,&k);
for(int i=1; i<=n; i++)
{
scanf("%d",&a[i]);
}
int s = 0;
int st = 1;
ll ans = 0; //用long long 保存,不然会爆内存。
for(int i=1; i<=n; i++)
{
if(a[i]>=m) s++;
if(s==k)
{
while(a[st]<m)
{
st++;
ans += (n-i+1);
}
ans += (n-i+1);
s--;
st++;
}
}
printf("%lld\n",ans);
}
return 0;
}