CSU 2281 dp或暴力二分

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

猜你喜欢

转载自blog.csdn.net/xiji333/article/details/89738372