【Asia Yokohama Regional Contest 2018】Arithmetic Progressions

题目大意:给定 N(1<N<=5000) 个不同元素组成的集合,求从中选出若干数字组成的等差数列最长是多少。

题解:直接暴力有 \(O(n^3)\) 的算法,即:枚举等差数列的前两个值,再暴力枚举后面的值进行匹配即可,不过这样做直接去世。。
考虑 \(dp[i][j]\) 表示以第 i 个数为数列倒数第二位,第 j 个数为等差数列中的最后一位的最长序列的长度,则:\(dp[i][j]=max\{dp[l][i]+1,a[i]-a[l]=a[j]-a[i]\&\&0<l<i\}\)。不过这样还是要枚举 l 进行转移,考虑序列是有序的,对于外层枚举的 i 来说,j 的枚举过程中 i 是不变的,且 a[j] 的值是单调递增的,可以利用单调性,令 l 不断减小,即可得到答案,均摊复杂度为 \(O(n^2)\)

代码如下

#include <bits/stdc++.h>
using namespace std;
const int maxn=5010;

int n,a[maxn],dp[maxn][maxn],ans;

int main(){
	scanf("%d",&n);
	for(int i=1;i<=n;i++)scanf("%d",&a[i]);
	sort(a+1,a+n+1);
	for(int i=1;i<=n;i++){
		int l=i-1;
		for(int j=i+1;j<=n;j++){
			dp[i][j]=2;
			while(l>=1&&a[j]-a[i]>a[i]-a[l])--l;
			if(l>=1&&a[j]-a[i]==a[i]-a[l])dp[i][j]=max(dp[i][j],dp[l][i]+1);
			ans=max(ans,dp[i][j]);
		}
	}
	printf("%d\n",ans);
	return 0;
}
posted @ 2019-03-31 19:04  shellpicker  阅读(544)  评论(0编辑  收藏  举报