等差数列(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;
}
posted @ 2022-04-29 14:45  ccz9729  阅读(195)  评论(0编辑  收藏  举报