AtCoder Context ABC 130 D Enough Array(足够长数组)

运行要求
运行时间限制: 2sec
内存限制: 1024MB
原题链接
D - Enough Array
题目
有一个长为N的整数数组A= a1,a2,a3,...,an和整数K。数组A中满足以下条件的连续的区间有几个。

  • 连续区间的和要大于等于K *

对于两个区间就算元素值是一样的,如果元素的所属位置不一样的话,这样区间按照两个不同区间去对待。
输出的值可能不能通过32bit装下。

要求

  • 1 <= ai <= 100000
  • 1 <= N <= 1000000
  • 1 <= K <= 10000

输入
输入都以以下标准从命令行输入

N K
a1 a2 a3 ... aN

输出
输出满足条件的连续区间的数量

例1
输入

4 10
6 1 2 7

输出

2
  • A[1..4] a1,a2,a3,a4(连续区间的和为16)
  • A[2..4] a2,a3,a4(连续区间的和为10)

满足条件的连续区间的数量为2

例2
输入

3 5
3 3 3

输出

3

对于两个区间就算元素值是一样的,但是元素的所属位置不一样,这样区间按照两个不同区间去对待。

例3
输入

10 53462
103 35322 232 342 21099 90000 18843 9010 35221 19352

输出

36

解题思路

读懂题目

1. 简单来说就是在一个数组里,找到连续的区间,并且连续的区间的和要小于给定值

思路

1. 找区间就意味着在数组内找两个点

AtCoder Context ABC 130 D Enough Array(足够长数组)_第1张图片

2. 直觉可以告诉我,找到大于等于K的区间的话,要遍历到最后,而反过来找小于K的区间的话,只要遍历一部分(这个看完后就明白了)

3. 长度为N的数组,取出所有两个点的组合有n(n-1)/2种情况这里N=4为例,总共有(4(4-1)) /2 = 6种情况
AtCoder Context ABC 130 D Enough Array(足够长数组)_第2张图片

4.最后的结果就是 第3步减去第2步的值,也就是所有取出两个元素的情况数 - 总和小于K的区间数

5.方法
1. 遍历每个元素,以遍历到的元素为开头,寻找后面的的值,直到区间的值大于等于K
这样的话就是循环里面套循环了,对于N最大值为10的5次方来说,这样的循环里面套循环的话复杂度为O(N2)时间上是不允许的,我第一次提交直接TLE了。

2. 尺取法(日文),Two Pointer Algorithm 这样的话复杂度只有O(N),时间上是允许的。
那么我们以例1为例子

AtCoder Context ABC 130 D Enough Array(足够长数组)_第3张图片

AtCoder Context ABC 130 D Enough Array(足够长数组)_第4张图片

AtCoder Context ABC 130 D Enough Array(足够长数组)_第5张图片

AtCoder Context ABC 130 D Enough Array(足够长数组)_第6张图片

AtCoder Context ABC 130 D Enough Array(足够长数组)_第7张图片

AtCoder Context ABC 130 D Enough Array(足够长数组)_第8张图片

AtCoder Context ABC 130 D Enough Array(足够长数组)_第9张图片

AtCoder Context ABC 130 D Enough Array(足够长数组)_第10张图片

AtCoder Context ABC 130 D Enough Array(足够长数组)_第11张图片

AtCoder Context ABC 130 D Enough Array(足够长数组)_第12张图片

AtCoder Context ABC 130 D Enough Array(足够长数组)_第13张图片

AtCoder Context ABC 130 D Enough Array(足够长数组)_第14张图片

AtCoder Context ABC 130 D Enough Array(足够长数组)_第15张图片

代码

S = input().split(" ")
n = int(S[0])
k = int(S[1])
S = input().split()
 
arr = [int(s) for s in S]
 
 
def calculate(n,k,arr):
    j = 0
    s = 0
    ans = 0
    for i in range(n):
        while (j < n) and (s + arr[j] < k):
            s = s + arr[j]
            j = j + 1
 
        ans = ans + j - i
 
        s = s - arr[i]
 
 
    print(n + (n * (n-1))//2 - ans)
 
 
calculate(n,k,arr)

总结
这道题可以作为Two Pointer Algorithm的练习题。
在左区间边界做传统for循环遍历的时候,对右区间边界范围进行Two Pointer Algorithm的计算可以将时间大大缩小。复杂度从O(N2)降为O(N)
另外,在二分法也可适用,目前还没有尝试。

※ 另外,我会在我的微信个人订阅号上推出一些文章,欢迎关注
AtCoder Context ABC 130 D Enough Array(足够长数组)_第16张图片


你可能感兴趣的:(python)