LIS の亜種だけど、雰囲気違って面白い!
問題概要
長さ の正の整数列 が与えられる。この部分列であって
- 狭義単調増加
- 後の index に出てくるやつは前の index にでてくるやつの倍数になっている
という条件を満たすものの最長の長さを求めよ。
制約
考えたこと
単純に DP しよう。
- dp[ v ] := 今見ている値が v のとき、v を最後の要素としたときの最長の長さ
として、v の約数 d (< v) を全部見て
- chmax(dp[ v ], dp[ d ] + 1)
とすればよい。v = 1 のときは dp[ v ] = 1 とする。計算量は となる。
#include <bits/stdc++.h> using namespace std; template<class T> inline bool chmax(T& a, T b) { if (a < b) { a = b; return 1; } return 0; } template<class T> inline bool chmin(T& a, T b) { if (a > b) { a = b; return 1; } return 0; } vector<long long> divisor(long long n) { vector<long long> res; for (long long i = 1; i * i <= n; ++i) { if (n % i == 0) { res.push_back(i); long long j = n / i; if (j != i) res.push_back(j); } } sort(res.begin(), res.end()); return res; } const int MAX = 310000; int main() { int N; cin >> N; vector<int> A(N); for (int i = 0; i < N; ++i) cin >> A[i]; vector<int> dp(MAX, 0); for (auto a : A) { if (a == 1) dp[a] = 1; else { const auto& div = divisor(a); for (auto d : div) if (d < a) chmax(dp[a], dp[d] + 1); } } int res = 0; for (int i = 0; i < MAX; ++i) chmax(res, dp[i]); cout << res << endl; }