HDU 5806 NanoApe Loves Sequence Ⅱ (滑动窗口 或者 二分法)

32 篇文章 0 订阅
5 篇文章 0 订阅

NanoApe Loves Sequence Ⅱ

Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 262144/131072 K (Java/Others)
Total Submission(s): 797    Accepted Submission(s): 376



Problem 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.

1T10, 2n200000, 1kn/2, 1m,Ai109
 

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
 

Source
 

大体题意:
给你n,m,k,并且给你n 个数列,问有多少个区间满足第k大的数不小于m?
思路:
两种思路,滑动窗口或者二分法!
其实两种思路的大体思路是一样的。
枚举区间的起点,这样只需要找到有多少个终点满足即可! 首先这个终点肯定是要大于等于  i + k - 1 的,(必须保证这个区间内有k个数),
关于滑动窗口:
先找到第一个终点满足大于等于k个数并且 符合条件的数等于k,然后起点在移动,起点移动找到第一个符合条件的数小于k个,并且l < r  这样ans += n- (r-1)+1。 依次循环即可! 详细见代码。
关于二分法:
可以先预处理,令sum[r]表示1,2,3,,r之间有多少个数字符合条件(即数字大于等于m)。
同样的去枚举起点i,在i+k-1  到 n 之间进行二分法,找到左边界符合条件的位置l, ans += n-l+1即可!
详细见代码:

滑动窗口版:
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn = 200000 + 10;
typedef long long ll;
int a[maxn];
int main(){
    int T;
    scanf("%d",&T);
    while(T--){
        int n,m,k;
        scanf("%d %d %d",&n,&m,&k);
        for (int i = 1; i <= n; ++i)scanf("%d",&a[i]);
        ll sum = 0ll;
        int l = 1,r = 1;
        int isok = 0;
        while(1){
            int sum1=0,sum2 =0;
            for (; r <= n && isok < k; ++r){
                if (a[r] >= m)++isok;
                ++sum1;
            }
            for (; l <= r && isok >= k; ++l){
//                printf("%d %d\n",l,r);
                sum += n-(r-1)+1;
                if (a[l] >= m)--isok;
                ++sum2;
            }
            if (!sum1 && !sum2)break;
        }
        printf("%I64d\n",sum);
    }
    return 0;
}

二分法版:

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn = 200000 + 10;
typedef long long ll;
int a[maxn];
int sum[maxn];
int n,m,k;
bool judge(int l,int r){
    return sum[r]-sum[l-1] >= k;
}
int main(){
    int T;
    scanf("%d",&T);
    while(T--){

        scanf("%d %d %d",&n,&m,&k);
        for (int i = 1; i <= n; ++i){
            scanf("%d",&a[i]);
            if (a[i] >= m)sum[i] = sum[i-1] +1;
            else sum[i] = sum[i-1];
        }
        ll ans = 0ll;
        for (int i = 1; i <= n; ++i){
            if (i + k-1 > n)break;
            if (!judge(i,n))continue;
            int l = i+k-1,r = n;
            int mid;
            while(l < r){
                mid = l+r >> 1;
                if (judge(i,mid))r=mid;
                else l = mid+1;
            }
//            printf("mid = %d\n",l);
            ans += n-l+1;
        }
        printf("%I64d\n",ans);
    }
    return 0;
}


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 6
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值