HDU - 5806 - NanoApe Loves Sequence Ⅱ(尺取+尺取法法介绍+时间复杂度讲解)

题目链接: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;
}

猜你喜欢

转载自blog.csdn.net/Alibaba_lhl/article/details/81267843