对于求数对问题的一个优化的小技巧

题目大意:
第二次萌新赛 数对

1.时间复杂度需要控制在 n ∗ l o g n n*logn nlogn之内

思路:
这道题让我们去求的数对的数量 , 根据 a l + a l + 1 + . . . + a r − 1 + a r < = x + y ∗ ( r − l + 1 ) a_l + a_{l + 1} + ...+a_{r - 1} +a_r <= x + y *(r - l + 1 ) al+al+1+...+ar1+ar<=x+y(rl+1) 这个条件我们需要进行一个处理, 将右边第二项移到左边,从整个序列来说我们需要去将每一项都减去y之后再查询新的每一个区间是否满足区间和小于等于 x x x 即可.但这个查询如果暴力来做的话会直接超时, 我们可以这样考虑:对于每一个 s u m [ i ] sum[i] sum[i]我们将它前面的i - 1 个数都按从大到小的顺序插入到vector容器中(使用low_bound 函数辅助实现) , 那么对于任意一个 j , j < i j , j < i jj<i 来说 ,题目要求也就是 求 s u m [ i ] − s u m [ j ] < = x sum[i] - sum[j] <= x% sum[i]sum[j]<=x , 也就是我们需要求对于未插入容器的 s u m [ i ] sum[i] sum[i] 来说 只要求的满足 s u m [ i ] − x < = s u m [ j ] sum[i] - x <= sum[j] sum[i]x<=sum[j] j j j 的个数就行了。 也就是这样一行代码

res += mp.size() - (lower_bound(mp.begin() , mp.end() , sum[i] - x ) - mp.begin() ) ;

2.需要注意的一些点:
我们需要初始化一下vector容器 , 要先向容器中插入一个0 这是非常容易忽略的一点为什么需要向容器中先加入一个0呢?
对于 s u m [ i ] − x sum[i] - x sum[i]x 这个式子来说, 我们考虑一种特殊的情况 , 就是前i个元素的和都小于等于x的话(也就是j = 0 ) 如果不添加这个零的话我们考虑的就只是从1 ~ i 的 的子区间去选而不包括[1, i] 这个最大的区间。 如果添加上0之后我们就能去求解这个满足条件的个数了。

代码:

#include <iostream>
#include <vector>
#include <algorithm>
#include <bits/stdc++.h>
using namespace std ;
typedef long long LL ;
const LL N = 2e5 + 10 ; 
vector<LL> mp ; 
LL a[N] , sum[N] ; 
LL  n , x , y ; 
signed main()
{
    cin >> n >> x >> y ; 
    LL res = 0 ;  
    for(int i = 1; i <= n ; i ++ )  
    {
        cin >> a[i] ; 
        sum[i] += sum[i - 1] - y + a[i] ;
    }
    mp.push_back(0) ; 
    for(int i = 1 ; i <= n ; i ++ )
    {
        res += mp.size() - (lower_bound(mp.begin() , mp.end() , sum[i] - x ) - mp.begin() ) ; 
        mp.insert(lower_bound(mp.begin() , mp.end() , sum[i] ) , sum[i] ) ; 
    }
    cout << res << endl ;
    return 0 ; 
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值