Description
NanoApe, the Retired Dog, has returned back to prepare for for the National Higher Education Entrance Examination!
In math class, NanoApe picked up sequences once again. He wrote down a sequence with n numbers and a number m on the paper.
Now he wants to know the number of continous subsequences of the sequence in such a manner that the k-th largest number in the subsequence is no less than m.
Note : The length of the subsequence must be no less than k.
Input
The first line of the input contains an integer T, denoting the number of test cases.
In each test case, the first line of the input contains three integers n,m,k.
The second line of the input contains n integers A1,A2,...,An, denoting the elements of the sequence.
1≤T≤10, 2≤n≤200000, 1≤k≤n/2, 1≤m,Ai≤109
Output
For each test case, print a line with one integer, denoting the answer.
Sample Input
1
7 4 2
4 2 7 7 6 5 1
Sample Output
18
题意就是 给你n个数,和一个m,k代表要选取子串,子串的第k大的值要大于等于m
利用乘法原理,可以得出答案
一个序列内只要有k个比m大的数就ok了,怎么求这个序列的总数呢?
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <queue>
using namespace std;
#define N 200050
int a[N];
long long d[N];
int main()
{
int T,n,m,k;
scanf("%d",&T);
while(T--)
{
scanf("%d %d %d",&n,&m,&k);
int t=0;
long long sum=0;
for(int i=1; i<=n; i++)
{
scanf("%d",&a[i]);
if(a[i]>=m)
{
d[++t]=i;
if(t>=k)//首先统计出k个比m大的
{
if(t==k) sum+=d[1]*(n-i+1);//这个时候,就是第一个大于m的位置i,乘以i以后的数
//相当于求出了这一段区间的总个数了
else sum+=(d[t-k+1]-d[t-k])*(n-i+1);//然后怎么求出以后的序列个数而且保证不重复呢?
//就要从前往后推理
//就是前一个-再前一个的距离*后面的数,就是这序列总数,可以画图看一下
//每次用倒数第二个位置-倒数第一个位置的差乘上后面的数
}
}
}
printf("%lld\n",sum);
}
return 0;
}
利用二分法,也是要统计前缀和
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<string>
#include<vector>
#include <ctime>
#include<queue>
#include<set>
#include<map>
#include<stack>
#include<iomanip>
#include<cmath>
#include<bitset>
#define mst(ss,b) memset((ss),(b),sizeof(ss))
typedef long long ll;
typedef long double ld;
#define INF (1ll<<60)-1
#define Max 1e9
using namespace std;
int n,k;
ll m;
ll a[200100];
int sum[200100];
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
scanf("%d%I64d%d",&n,&m,&k);
for(int i=1; i<=n; i++)
scanf("%I64d",&a[i]);
sum[0]=0;
for(int i=1; i<=n; i++)
{
if(a[i]>=m)
sum[i]=sum[i-1]+1;//统计>=m的前缀和
else
sum[i]=sum[i-1];
}
ll ans=0;
for(int i=1; i+k-1<=n; i++)
{//
int l=i+k-1,r=n,mid,f=-1;//区间的开头从1开始枚举
while(l<=r)//最低是k个数啊
{
mid=(l+r)/2;
if(sum[mid]-sum[i-1]>=k)
{
r=mid-1;
f=mid;
}
else
l=mid+1;//
}
if(f==-1)
continue;
else
ans+=1LL*(n-f+1);//累计符合条件的子串长度
//printf("%d %d\n",i+k-1,n-f+1)
}
printf("%I64d\n",ans);
}
return 0;
}
利用尺取法也是