http://acm.csu.edu.cn:20080/csuoj/problemset/problem?pid=2281
Description
An arithmetic progression is a sequence of numbers a1, a2, ..., ak where the difference of consecutive members ai + 1 − ai is a constant 1 ≤ i ≤ k − 1 . For example, the sequence 5, 8, 11, 14, 17 is an arithmetic progression of length 5 with the common difference 3.
In this problem, you are requested to find the longest arithmetic progression which can be formed selecting some numbers from a given set of numbers. For example, if the given set of numbers is {0, 1, 3, 5, 6, 9}, you can form arithmetic progressions such as 0, 3, 6, 9 with the common difference 3, or 9, 5, 1 with the common difference -4. In this case, the progressions 0, 3, 6, 9 and 9, 6, 3, 0 are the longest.
Input
The input consists of a single test case of the following format.
n
v1 v2 ... vn
n is the number of elements of the set, which is an integer satisfying 2 ≤ n ≤ 5000 . Each vi(1 ≤ i ≤ n) is an element of the set,which is an integer satisfying 0 ≤ vi ≤ 109.vi's are all different, i.e.,vi ≠ vj if i ≠ j
Output
Output the length of the longest arithmetic progressions which can be formed selecting some numbers from the given set of numbers.
Sample Input
6 0 1 3 5 6 9
Sample Output
4
Hint
Source
题目大意:输出最长的等差数列的长度。
思路:最容易想到的,暴力二分。卡着时间线过的。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<queue>
#include<algorithm>
using namespace std;
int n;
int a[5005];
int main()
{
scanf("%d",&n);
for(int i=0;i<n;i++)
scanf("%d",&a[i]);
int MAX=0;
int temp,cnt,t;
sort(a,a+n);
for(int i=0;i<n;i++)
{
if(n-i<=MAX)
break;
if(i>0&&a[i]==a[i-1])
continue;
for(int j=i+1;j<n;j++)
{
if(n-j+1<=MAX)
break;
if(j>i+1&&a[j]==a[j-1])
continue;
int d=a[j]-a[i];
if(d!=0)
{
temp=a[j];
cnt=2;
t=lower_bound(a,a+n,temp+d)-a;
while(t!=n)
{
if(a[t]==temp+d)
{
temp+=d;
++cnt;
t=lower_bound(a,a+n,temp+d)-a;
}
else
break;
}
if(cnt>MAX)
MAX=cnt;
}
else
{
cnt=2;
for(int k=j+1;k<n;k++)
{
if(a[k]!=a[k-1])
{
i=k-2;
break;
}
++cnt;
}
if(cnt>MAX)
MAX=cnt;
}
}
}
printf("%d\n",MAX);
return 0;
}
另外一种思路:dp,用dp[i][j]表示最后两项是a[i]和a[j]的等差数列的长度,若我们能找到一个pre满足pre<i&&a[i]-a[pre]=a[j]-a[i],那么有dp[i][j]=max(dp[i][j],dp[pre][i]+1)。同时巧妙的利用了数组有序的性质。
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#define INF 0x3f3f3f3f
using namespace std;
typedef long long ll;
int dp[5005][5005];
int a[5005];
int n;
int main()
{
scanf("%d",&n);
for(int i=0;i<n;i++)
scanf("%d",&a[i]);
sort(a,a+n);
int d,pre;
int MAX=0;
for(int i=0;i<n-1;i++)
{
pre=i-1;
for(int j=i+1;j<n;j++)
{
d=a[j]-a[i];
while(pre>=0&&a[i]-a[pre]<d)
--pre;
if(pre<0||a[i]-a[pre]!=d)
dp[i][j]=2;
else
dp[i][j]=max(dp[i][j],dp[pre][i]+1);
MAX=max(MAX,dp[i][j]);
}
}
printf("%d\n",MAX);
return 0;
}