はじめに
AtCoder Problems の Recommendation を利用して、過去の問題を解いています。
AtCoder さん、AtCoder Problems さん、ありがとうございます。
今回のお題
AtCoder Beginner Contest D - Enough Array
Difficulty: 859
今回のテーマ、累積和 + 二分探索
問題文(条件)連続部分列に含まれる全ての要素の値の和は、K 以上である。より累積和を使用することが分かりますが、1≦N≦100_000ですので2重にループを回すとTLEになります。
そこで、累積和は単調増加ですので、計算量を抑えるために二分探索も併用します。
Ruby
n, k = gets.split.map(&:to_i)
a = gets.split.map(&:to_i)
acc = 0
x = [0] + a.map{|v| acc += v}
cnt = 0
x.each do |y|
j = x.bsearch_index{|z| z - y >= k}
if j == nil
break
else
cnt += n - j + 1
end
end
puts cnt
acc = 0
x = [0] + a.map{|v| acc += v}
累積和はここで計算しています。
追記
コメントでいただいたコードに修正しました。
j = x.bsearch_index{|z| z - y >= k}
二分探索ですが、C++ でいうところのlower_boundが、Ruby ではbsearch若しくはbsearch_indexになります。
Python
from sys import stdin
def main():
import bisect
import itertools
input = stdin.readline
n, k = map(int, input().split())
a = list(map(int, input().split()))
x = [0] + list(itertools.accumulate(a))
cnt = 0
for z in x:
j = bisect.bisect_left(x, k + z)
if j <= n:
cnt += n - j + 1
print(cnt)
main()
x = [0] + list(itertools.accumulate(a))
Python では、累積和を求めるaccumulateという関数があります。
j = bisect.bisect_left(x, k + z)
二分探索ですが、bisect若しくはbisect_left bisect_rightを使用します。
探索する数値が配列に含まれる場合、bisectはその数値の右側、bisect_leftは左側の位置を返します。
for z in x:
for i in range(n):
range()でループを回すとTLEしました。
| Ruby | Python | |
|---|---|---|
| コード長 (Byte) | 238 | 377 |
| 実行時間 (ms) | 165 | 101 |
| メモリ (KB) | 11780 | 14196 |
まとめ
- ABC 130 D を解いた
- Ruby に詳しくなった
- Python に詳しくなった
参照したサイト
instance method Array#bsearch
すごいぞitertoolsくん
bisect --- 配列二分法アルゴリズム