题意:求最长等差序列的长度。
分析:思考一下,一旦确定等差序列中的两个相邻的点在原序列中的位置,那么我们可以藉此 线性时间内找出完整的等差序列 (因为差已经确定,向前向后找就可以了)
我们设枚举了 i,j (i<j) 两个点,公差 dif = a[j] - a[i] , 显然 ,向前找到第一个位置 z (z<i) 使得 a[i] - a[z] = dif ,那么等差序列长度 +1 ,然后继续往前找。
这样纯暴力肯定不行,所以我们现在希望找到位置 z 之后就能得到 包含 z 以 z 结尾并以 dif 为公差的最长等差序列,这样我们直接接上长度就可以了,可以极大优化。
怎么记录状态,设 dp[i][j] (i<j) 为以 a[j]-a[i] 为公差且以位置 j 结尾的最长等差序列长度,那么找到位置 z 后,显然:
dp[i][j] = dp[z][i] + 1;
代码:
#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
const int N = 5000+10;
int s[N];
int dp[N][N]={{0}};
int main()
{
int n,ans=0;
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d",&s[i]);
sort(s+1,s+n+1);
for(int i=1;i<n;i++)
{
int l=i-1; //这个不能放在循环里面,会T
for(int j=i+1;j<=n;j++)
{
dp[i][j]=2;
int dis=s[j]-s[i];
while(l>0&&dis>s[i]-s[l]) l--;
if(l>0&&dis==s[i]-s[l])
{
dp[i][j]=dp[l][i]+1;
}
ans=max(ans,dp[i][j]);
}
}
printf("%d",ans);
}