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】
设
表示:以第 i 项和第 j 项(i>j)作为数列最后两项,的最长长度。
转移就是找一个 k,使得
,然后就
。
三个变量的枚举,所以是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;
}