配点: 300 点 / 実行時間制限: 2 sec / メモリ制限: 1024 MB / Difficulty: 161
問題概要
長さ の整数列
が与えられるので、
の空でない連続部分列であって、同じ値を複数個含むようなものが存在するか判定せよ。もし存在するならば、そのようなもののうち最も短いものの長さを求めよ。
制約
- 入力はすべて整数。
考察
条件を満たす の連続部分列は、左端と右端の数字が必ず同じになる。
もし左右端の文字が異なるならば、「左端を1つ右にずらす」 or 「右端を1つ左にずらす」ことを行って、長さを 減らすことができるからだ。
さて、ある数字 を右端として定めたとき、左端のインデックスは
を満たす
であり、このときの連続部分列の長さは
と計算できる。
したがって、各 について上述の条件を満たす
を探せばよい。
ただし、この を探すために毎回
for
ループを使っていては、全体の計算量が となって TLE してしまう。
そこで、直前に が現れたインデックスを記録しておく配列
を用意しておく。
直近で数
が
に現れたインデックス(初期値は
)
その上で、もし であれば、
とできる。
このようにして、全体の計算量を に落とすことができた。
実装例
#include <bits/stdc++.h> using namespace std; constexpr int INF = 1e+9; #define rep(i, start, end) for (auto i = (start); (i) < (end); (i)++) template <typename T> inline bool chmin(T &a, T b) { return ((a > b) ? (a = b, true) : (false)); } // ======================================== // int main() { int N; cin >> N; vector<int> A(N); rep(i, 0, N) cin >> A[i]; vector<int> pos(1000100, -1); int ans = INF; rep(i, 0, N) { if (pos[A[i]] != -1) chmin(ans, i - pos[A[i]] + 1); pos[A[i]] = i; } if (ans == INF) cout << -1 << endl; else cout << ans << endl; return 0; }
実装時間: 10分
コメント
「配列のインデックスを別の配列に記録する」という考え方は、計算量改善の上で重要。