等差数列(DP)
题目链接 \(-\) 题目-最长等差数列 (51nod.com)
本题 很容易 得出一个 \(n^2 \log n\) 的解法,令 \(dp[i][j]\) 表示以 \(i\) 结尾,公差为 \(j\) 的最长等差数列的长度,由于公差太大,因此我们需要用到 \(map\) ,即 用 \(map<int,int> mp[MAXN]\) 来进行 \(dp\) ,因此复杂度为 \(n^2 \log n\) 。
显然上述做法是会 \(TLE\) 的。
我们考虑去优化上面的 \(dp\) 。
对于一个等差数列的连续三项 \(a_i, a_j, a_k\) ,他们满足一个式子 \(2 * a_j = a_i + a_k\) ,那么我们可以定义 \(dp[i][j]\) 表示以 \(a_i, a_j\) 为最后两项的最长等差数列的长度。
对于一个有序数组 \(a\) 来说,我们可以枚举 \(i\),然后从利用双指针进行 \(dp\) ,令 \(L = i - 1, R = i + 1\),每次判断 $a_i * 2 $ 和 \(a_L + a_R\) 的值
- \(a_i * 2 == a_L + a_R\) 直接更新 \(dp[i][R] = max(dp[i][R], dp[L][i] + 1)\),然后令 \(L--\) ,继续更新 \(dp\) 数组
- \(a_i * 2 > a_L + a_R\) 由于 \(a_i\) 过大,那么我们需要令 \(R++\) ,使得 \(a_L + a_R\) 的值增加
- \(a_i * 2 < a_L + a_R\) 由于 \(a_i\) 过小,那么我们需要令 $ L--,使得 \(a_L + a_R\) 的值减少
注意初始化:\(f[i][j](i < j)\) 均为 \(2\)
#include <bits/stdc++.h>
using namespace std;
const int N = 5001;
int a[N];
int f[N][N];
signed main() {
int n; scanf("%d", &n);
for(int i = 1; i <= n; i ++ ) {
scanf("%d", a + i);
}
if(n <= 2) {
printf("%d\n", n); return 0;
}
sort(a + 1, a + 1 + n);
int ans = 2;
for(int i = 1; i <= n; i ++ ) {
for(int j = i + 1; j <= n; j ++ ) {
f[i][j] = 2;
}
}
for(int i = 1; i <= n; i ++ ) {
int L = i - 1, R = i + 1;
while(L >= 1 && R <= n) {
if(a[i] * 2 == a[L] + a[R]) {
f[i][R] = max(f[i][R], f[L][i] + 1);
ans = max(ans, f[i][R]);
L --;
} else if(a[i] * 2 > a[L] + a[R]) {
R ++;
} else {
L --;
}
}
}
printf("%d\n", ans);
return 0;
}