実行時間制限: 2 sec / メモリ制限: 1024 MB / Difficulty: 666
問題概要
周期 をもつ無限数列 の先頭 項 が与えられる。この数列の空でない連続する部分列のうち、和が となるものが存在するか判定せよ。
制約
- 入力はすべて整数。
考察
和が となる の連続部分数列を 、 の1周期分の数列を とする。このとき、 は先頭から以下のようなグループに分けられる。
- から の部分。
- を 回以上繰り返した部分。すなわち、 から の部分。
- から の部分。
このうち、2番目の部分については、 を取ることで無視することができる。
したがって、 とすれば、残りの部分は長さが 以下となり、この問題を以下のように言い換えることができる。
- の長さ 以下の連続部分数列であって、総和が となるものを求めよ。
このパターンは2周期分の累積和を取るのが有効。すなわち、 とすれば、
- 数列 において、 を満たす組 が存在するか判定せよ。
と、上記の問題をさらに言い換えることができる。
これは の制約から愚直な線形探索は厳しいが、累積和の数列 が単調増加数列であることに注目すると、二分探索を使って で判定を行うことができる。
コード
#include <bits/stdc++.h> using namespace std; using ll = long long; #define all(x) (x).begin(), (x).end() #define rep(i, start, end) for (auto i = (start); (i) < (end); (i)++) // ======================================== // int main() { int N; ll S; cin >> N >> S; ll cycle_sum = 0; vector<ll> A(N * 2); rep(i, 0, N) cin >> A[i], A[i + N] = A[i], cycle_sum += A[i]; ll remain = S % cycle_sum; vector<ll> ps(N * 2 + 1, 0); rep(i, 0, N * 2) ps[i + 1] = ps[i] + A[i]; rep(i, 0, N) { if (binary_search(all(ps), ps[i] + remain)) { cout << "Yes" << endl; return 0; } } cout << "No" << endl; }
実装時間: 30分