51nod1055·最长等差数列
题面
题目描述
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。
输入
第1行:N,N为正整数的数量(3 <= N <= 10000)。
第2 - N+1行:N个正整数。(2<= A[i] <= 10^9)
输出
最长等差数列的长度。
输入样例
10
1
3
5
6
8
9
10
12
13
14
输出样例
5
题解
显然是一道动态规划。
由于要等差数列,因此需要排序。
设 f [ i ] [ j ] f[i][j] f[i][j]为:第 i i i个数字作为等差数列的倒数第二位,第 j j j的数字作为等差数列最后一位的 最长等差数列。
必然,当 n ≥ 2 n≥2 n≥2时必然能够形成大小为 2 2 2的等差数列,故可得初始化 f [ ] [ ] = 2 f[\ ][\ ]=2 f[ ][ ]=2.我们需要通过动态规划来找出大于等于 3 3 3的长度的等差数列。
f
[
i
]
[
j
]
=
f
[
k
]
[
i
]
+
1
f[i][j]=f[k][i]+1
f[i][j]=f[k][i]+1.表示以j结尾的等差数列添上第i位。这里保证
k
<
j
<
i
k<j<i
k<j<i且
a
[
j
]
+
a
[
k
]
=
2
∗
a
[
i
]
a[j]+a[k]=2*a[i]
a[j]+a[k]=2∗a[i].
如果枚举每一个ijk,复杂度
O
(
n
3
)
O(n^3)
O(n3),妥妥的超时,所以我们可以优化枚举的状态。即枚举每一个i,根据第二个约束条件的大小关系逐渐将
k
k
k向左,
j
j
j向右扫,并在达到平衡状态时进行转移。这样复杂度
O
(
n
2
)
O(n^2)
O(n2)。
i的枚举方式,即顺序枚举保证了 f [ k ] [ i ] f[k][i] f[k][i]的存在,即中间数 ( k + i ) / 2 < i (k+i)/2<i (k+i)/2<i。
C O D E CODE CODE
#include<bits/stdc++.h>
using namespace std;
const int maxn=10005;
int n;
int a[maxn];
short int ans=2;
short int f[maxn][maxn];
int main(void)
{
cin>>n;
for (int i=1;i<=n;++i) cin>>a[i];
for (int i=1;i<=n;++i)
for (int j=i+1;j<=n;++j)
f[i][j]=2;
sort(a+1,a+n+1);
for (int i=2;i<n;++i)
{
int k=i-1,j=i+1;
while (k>=1 && j<=n)
{
if (a[k]+a[j]<2*a[i]) j++;
else if (a[k]+a[j]>2*a[i]) k--;
else f[i][j]=f[k][i]+1,ans=max(ans,f[i][j]),k--,j++;
}
}
cout<<ans<<endl;
return 0;
}