b_51_最长等差数列(暴力dp / 双指针dp优化内存)

N个不同的正整数,找出由这些数组成的最长的等差数列(子序列)
3 <= N <= 10000

这题起初被数据吓得不敢用\(n^2\)解法,可是不用又怎么解呢?一气之下...MLE结束
思路:f[i][d]表示前i个数中公差为d的最长等差数列的长度,如果在a[i]-a[j]==d,j位置和i位置形成公差为2的等差数列,而j又可以和j前面的数形成等差,所以f[i][d]=f[j][d]+2;

#include<bits/stdc++.h>
#define rep1(i,s,e) for(register int i=s;i<=e;i++)
#define rep2(i,s,e) for(register int i=e;i>=s;i--)
using namespace std;
const int N=1e5+5;
int n,ans,a[N];
int main() {
    std::ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
    cin>>n; rep1(i,0,n-1) cin>>a[i];
    unordered_map<int, int> f[n];
    sort(a,a+n);
    rep1(i,0,n-1)
    rep1(j,0,i-1) {
        int d=a[i]-a[j];
        if (f[j][d]>0) f[i][d]=f[j][d]+1;
        else f[i][d]=2;
        ans=max(ans,f[i][d]);
    }
    cout<<ans;
    return 0;
}a

看到有空间更优的双指针+dp算法,学习了一下:f[i][j]表示以a[j]、a[i]为等差数列开始的两个数的最长长度

#include<bits/stdc++.h>
#define rep1(i,s,e) for(register int i=s;i<=e;i++)
#define rep2(i,s,e) for(register int i=e;i>=s;i--)
using namespace std;
const int N=10005; //写1e5就报错...
int n,ans=2,a[N];
short int f[N][N]; 
int main() {
    std::ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
    cin>>n; rep1(i,0,n-1) cin>>a[i];
    sort(a,a+n);
    rep1(i,0,n-2)
    rep1(j,i+1,n-1) 
        f[i][j]=2;
    
    rep1(i,1,n-2) {
        int j=i-1, k=i+1;
        while (j>=0 && k<n) {
            if (a[j]+a[k]<2*a[i]) k++;
            else if (a[j]+a[k]>2*a[i]) j--;
            else {
                f[i][k]=f[j][i]+1;
                if (f[i][k]>ans) ans=f[i][k];
                j--, k++;
            }
        }
    }
    cout<<ans;
    return 0;
}
posted @ 2020-10-25 15:49  童年の波鞋  阅读(95)  评论(0编辑  收藏  举报