时隔一个星期,重新看了这道题。放一下我们组队赛的脑洞:https://blog.csdn.net/iroy33/article/details/88871961
题意:给你一个数组,求用这个数组里面的数字,能构成的等差数列,最大有多长?
DP的思路:
代表的是以 和 结尾的等差数列。
如果在之前,存在一个数字,使得(d是公差),
那么有递推公式.
中间在test 56处,TLE了。几经修改,还是看了别人的代码,发现了端倪。
//Gym 102082B
//DP
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int maxn=5005;
long long num[maxn];
int dp[maxn][maxn];
int main()
{
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%lld",&num[i]);
}
sort(num+1,num+1+n);
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
dp[i][j]=2;
int ans=2;
for(int i=1;i<=n;i++)//pre,i,j
{
int pre=i-1;
for(int j=i+1;j<=n;j++)
{
int d=num[j]-num[i];
// int pre=i-1; 这里定义的话,会TLE on test 56
while(pre>=1 && num[i]-num[pre]<d)
pre--;
if(num[i]-num[pre]==d)
dp[i][j]=max(dp[i][j],dp[pre][i]+1);
ans=max(ans,dp[i][j]);
}
}
cout<<ans<<endl;
}
我们在寻找pre的时候,j的增加,会使公差d增大,pre可以从j-1次循环的地方继续,没有必要重新赋值查找。
所以,看到了另外一种写法:利用DP的递推式,在找pre的时候,使用二分。指路:dp+lower_bound.
哎呀,学弟都是大佬。
使用二分的话,就更简单了。
暴力双重循环 和 ,对于 和,向后找到公差为的数(找的时候,二分查找省时间呗,当然之前先排个序),看有多少个,更新一下结果。
//Gym 102082B
//二分
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int maxn=5005;
long long num[maxn];
int dp[maxn][maxn];
int main()
{
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%lld",&num[i]);
}
sort(num+1,num+1+n);
int ans=0;
int count=2;//数组长度
for(int i=1;i<=n;i++)
{
for(int j=i+1;j<=n;j++)
{
count=2;
int d=num[j]-num[i];
int later=num[j]+d;
while(1)
{
if(binary_search(num+1,num+n+1,later))
{
count++;
later=later+d;
}
else
{
ans=max(ans,count);
break;
}
}
}
}
cout<<ans<<endl;
}