CFR 566 F. Clique in the Divisibility Graph ( DP, Math, Complexity Analysis )
題意:
給一個嚴格遞增序列。求子序列最長長度,子序列滿足所有相鄰元素對,後一個元素可以被前一個整除。
資料規模:
序列長度 1 ≤ N ≤ 1e6
元素大小 1 ≤ A[ i ] ≤ 1e6
時限 1000 ms
記憶體 256 MB
解法:
注意到 [ 1, N ] 的數的因數個數總和約為 SIGMA{ 1 / i | 1 ≤ i ≤ N } = N lg N。因此可以直接開一個 dp 表,每一次對該元素的所有倍數更新。
dp[ i ] : 以 i 結尾的數,合法序列目前最長長度可以是多少
時間 / 空間複雜度:
O( N lg N )
閒話:
以前都一直聽動態規劃的時間複雜度就是狀態數 * 轉移維度。但最近才慢慢領悟,原來其實是 max{ 最大可能的須拜訪的狀態數, 最大可能的總轉移次數 }。
int N; vi A; void init(){ cin >> N; A = vi( N ); for( int i = 0; i < N; ++i ) cin >> A[ i ]; } int maxa; vi dp; void preprocess(){ maxa = *max_element( A.begin(), A.end() ); dp = vi( maxa + 1, 1 ); for( int i = 0; i < N; ++i ) for( int j = A[ i ] + A[ i ]; j <= maxa; j += A[ i ] ) upmax( dp[ j ], dp[ A[ i ] ] + 1 ); } void solve(){ int ans = 0; for( int i = 0; i < N; ++i ) upmax( ans, dp[ A[ i ] ] ); cout << ans << endl; }