题目:http://acm.hdu.edu.cn/showproblem.php?pid=5806
题意:
问题描述
退役狗 NanoApe 滚回去学文化课啦! 在数学课上,NanoApe 心痒痒又玩起了数列。他在纸上随便写了一个长度为 n 的数列,他又根据心情写下了一个数 m。 他想知道这个数列中有多少个区间里的第 k 大的数不小于 m,当然首先这个区间必须至少要有 k 个数啦。
输入描述
第一行为一个正整数 T,表示数据组数。 每组数据的第一行为三个整数 n,m,k。 第二行为 n 个整数 Ai,表示这个数列。 1≤T≤10, 2≤n≤200000, 1≤k≤n/2, 1≤m,Ai≤109
输出描述
对于每组数据输出一行一个数表示答案。
输入样例
1 7 4 2 4 2 7 7 6 5 1
输出样例
18思路:尺取法很简单
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <vector>
#include <cmath>
using namespace std;
typedef long long ll;
const int N = 200010;
int arr[N];
int main()
{
int t, n, m, k;
scanf("%d", &t);
while(t--)
{
scanf("%d%d%d", &n, &m, &k);
for(int i = 1; i <= n; i++)
scanf("%d", &arr[i]);
ll sum = 0;
int tip = 1, til = 1, cnt = 0;
while(til <= n)
{
if(arr[til] >= m) cnt++;
if(cnt >= k) sum += n - til + 1; //arr[tip~til]满足条件,那么arr[tip~(til+1~n)]中的任意一个自然也是满足条件的
while(cnt >= k) //左端点向右推进
{
if(arr[tip] >= m) cnt--;
if(cnt >= k) sum += n - til + 1; //若满足条件,加上区间数
tip++;
}
til++;
}
printf("%lld\n", sum);
}
return 0;
}
11月22日,看了别人的写的更简练的尺取,贴一下
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <vector>
#include <cmath>
using namespace std;
typedef long long ll;
const int N = 200010;
int arr[N];
int main()
{
int t, n, m, k;
scanf("%d", &t);
while(t--)
{
scanf("%d%d%d", &n, &m, &k);
for(int i = 1; i <= n; i++)
scanf("%d", &arr[i]);
ll sum = 0;
int til = 1, cnt = 0;
for(int i = 1; i <= n; i++)
{
while(til <= n && cnt < k)
if(arr[til++] >= m) cnt++;
if(cnt >= k) sum += n - til + 2;
if(arr[i] >= m) cnt--;
}
printf("%lld\n", sum);
}
return 0;
}