hdu 5806 乘法原理 || 尺取法 || 二分法

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;
}

利用尺取法也是

猜你喜欢

转载自blog.csdn.net/lanshan1111/article/details/87563264