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;
}