51nod 1055 最长等差数列 DP+数学

版权声明:https://blog.csdn.net/huashuimu2003 https://blog.csdn.net/huashuimu2003/article/details/88830297

title

51nod
描述 Description

N个不同的正整数,找出由这些数组成的最长的等差数列。
例如:1 3 5 6 8 9 10 12 13 14
等差子数列包括(仅包括两项的不列举)
1 3 5
1 5 9 13
3 6 9 12
3 8 13
5 9 13
6 8 10 12 14
其中6 8 10 12 14最长,长度为5。

输入格式 Input Format

第1行:N,N为正整数的数量(3 <= N <= 10000)。
第2 - N+1行:N个正整数。(2<= Ai <= 10^9)

输出格式 Output Format

最长等差数列的长度。

样例输入 Sample Input

10
1
3
5
6
8
9
10
12
13
14

样例输出 Sample Output

5

时间限制 Time Limitation

1s

注释 Hint

例如:1 3 5 6 8 9 10 12 13 14
等差子数列包括(仅包括两项的不列举)
1 3 5
1 5 9 13
3 6 9 12
3 8 13
5 9 13
6 8 10 12 14
其中6 8 10 12 14最长,长度为5。

来源 Source

刘世纪

analysis

【n3】

f [ i ] [ j ] f[i][j] 表示:以第 i 项和第 j 项(i>j)作为数列最后两项,的最长长度。
转移就是找一个 k,使得 a [ i ] a [ j ] = a [ j ] a [ k ] a[i]-a[j]=a[j]-a[k] ,然后就 f [ i ] [ j ] = f [ j ] [ k ] + 1 f[i][j]=f[j][k]+1
三个变量的枚举,所以是n^3。

【n2log】

我们观察,枚举了 i 和 j 之后,a[k] 的值是确定的。
那么搞个东西存下对于每个 j 同一类的 k 的最大 f 值就好了。
如果一开始离散化这个数组,那可以二分求这个 k,所以带个log。

【n2】

实际上不需要离散化也不需要二分,因为如果 j 从大到小枚举,那么 k 是单调递减的。
于是就 n^2 了。

——摘自rzO_KQP_Orz

code

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e4+5;
template<typename T>inline void read(T &x)
{
	x=0;
	T f=1, ch=getchar();
	while (!isdigit(ch) && ch^'-') ch=getchar();
	if (ch=='-') f=-1, ch=getchar();
	while (isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48), ch=getchar();
	x*=f;
}
int a[maxn];
short int f[maxn][maxn];//f[i][j]表示以i开始,以j结尾的等差数列的长度
int main()
{
	int n;read(n);
	for (int i=1; i<=n; ++i)
		read(a[i]);
	sort(a+1,a+n+1);
	int ans=0;
	for (int i=2; i<n; ++i)
	{
		int j=i-1,k=i+1;
		while (j>0 && k<=n)
		{
			if (a[j]+a[k]>(a[i]<<1))
				--j;
			else if (a[j]+a[k]<(a[i]<<1))
				++k;
			else
			{
				f[i][k]=f[j][i]==0?3:f[j][i]+1;
				if (ans<f[i][k])
					ans=f[i][k];
				--j,++k;
			}
		}
	}
	printf("%d\n",ans);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/huashuimu2003/article/details/88830297
今日推荐