#843. 等差数列
题目链接
#843. 等差数列
题目描述
给定一个大小为\(n\)的集合\(\{S\}\), 你可以从中挑选若干个数组成等差数列, 求最长的等差数列长度
输入描述
一行一个整数\(n\leq 5000\)
接下来一行\(n\)个整数\(|S_i| < {2^{31}}\), 描述集合\(\{S\}\)中的元素
输出描述
一行一个整数, 描述最长的等差数列的长度
样例输入
10
14 1 3 5 6 8 9 10 12 13
样例输出
5
样例解释
等差数列包括(仅包括两项的不列举)
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。
解题思路
dp
- 状态表示:\(f[i][j]\) 表示后等差数列后两项为 \(a[j]\) 和 \(a[i]\) 时的最长长度
二分
-
状态计算:此时,计算公差 \(d=a[i]-a[j]\),
-
- 如果前面存在 \(a[pos]=a[j]-d\) ,则 \(f[i][j]=f[j][pos]+1\)
-
- 否则,\(f[i][j]=2\)
-
时间复杂度:\(O(n^2logn)\)
双指针
设置等差数列的三项 \(a_L,a_i,a_R\),则有 \(a_R-a_i=a_i-a_L\),枚举中间的 \(i\),\(L\) 和 \(R\) 分别为左右指针,当存在 \(a_R-a_i=a_i-a_L\) 时转移状态 \(f[i][R]=max(f[i][R],f[L][i]+1)\),其中 \(f[L][i]\) 是已知的,因为 \(i\) 从小到大枚举且 \(L<i\),然后移动左右指针任意一个,当 \(a_R-a_i>a_i-a_L\),\(a_i-a_L\) 的公差偏小,\(L--\),反之,\(R++\)
- 时间复杂度:\(O(n^2)\)
代码
- 二分
// %%%Skyqwq
#include <bits/stdc++.h>
//#define int long long
#define help {cin.tie(NULL); cout.tie(NULL);}
#define pb push_back
#define fi first
#define se second
#define mkp make_pair
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
typedef pair<LL, LL> PLL;
template <typename T> bool chkMax(T &x, T y) { return (y > x) ? x = y, 1 : 0; }
template <typename T> bool chkMin(T &x, T y) { return (y < x) ? x = y, 1 : 0; }
template <typename T> void inline read(T &x) {
int f = 1; x = 0; char s = getchar();
while (s < '0' || s > '9') { if (s == '-') f = -1; s = getchar(); }
while (s <= '9' && s >= '0') x = x * 10 + (s ^ 48), s = getchar();
x *= f;
}
const int N=5005;
int n,a[N];
int f[N][N];
int main()
{
read(n);
for(int i=1;i<=n;i++)read(a[i]);
sort(a+1,a+1+n);
int res=n>=2?2:1;
for(int i=1;i<=n;i++)
for(int j=1;j<i;j++)
{
int d=a[i]-a[j];
int pos=upper_bound(a+1,a+1+n,a[j]-d)-a-1;
if(pos>=1&&pos<=n&&a[pos]==a[j]-d)
{
f[i][j]=f[j][pos]+1;
res=max(res,f[i][j]);
}
else
f[i][j]=2;
}
printf("%d",res);
return 0;
}
- 双指针
// %%%Skyqwq
#include <bits/stdc++.h>
//#define int long long
#define help {cin.tie(NULL); cout.tie(NULL);}
#define pb push_back
#define fi first
#define se second
#define mkp make_pair
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
typedef pair<LL, LL> PLL;
template <typename T> bool chkMax(T &x, T y) { return (y > x) ? x = y, 1 : 0; }
template <typename T> bool chkMin(T &x, T y) { return (y < x) ? x = y, 1 : 0; }
template <typename T> void inline read(T &x) {
int f = 1; x = 0; char s = getchar();
while (s < '0' || s > '9') { if (s == '-') f = -1; s = getchar(); }
while (s <= '9' && s >= '0') x = x * 10 + (s ^ 48), s = getchar();
x *= f;
}
const int N=5005;
int n,a[N];
int f[N][N];
int main()
{
read(n);
for(int i=1;i<=n;i++)read(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+1+n);
int res=n>=2?2:1;
for(int i=1;i<=n;i++)
{
int L=i-1,R=i+1;
while(L>=1&&R<=n)
{
if(a[R]-a[i]==a[i]-a[L])
{
f[i][R]=max(f[i][R],f[L][i]+1);
res=max(res,f[i][R]);
L--;
}
else if(a[R]-a[i]>a[i]-a[L])L--;
else
R++;
}
}
printf("%d",res);
return 0;
}