题意:给定一组数,求能组成的最长的等差数列是多少?
看到有人说这是一个模板题,(ΩДΩ),刷题刷太少了嘛_(:з」∠)_
和队友想到一个蛇皮的状态定义和转移方程,一直wa在test 11,感谢roMxx提供的样例
定义表示num[j]为以num[i]为首项的第
项,t是由此计算出的公差
but! dp[0][3]依赖dp[0][2]的结果,但是dp[0][2]已经形成num[0],num[1],num[2]这三项,导致建立不起num[0] num[2] num[3]的数组,即后面的更优解更新不到,所以我们的状态转移方程错了。。。一开始想了半天没想出来最优子结构在哪
另一个队友一开始说二分,我们没想到咋二分,然后看到这个博客提供了二分的思路,就是枚举首项和第二项,去找多少个数,超赞啊、、、
dp的思路就是枚举最后两项,向前找。
仔细想了想,觉得最优子结构在于a1,a2,a3,如果这三项能构成等差 a0,a1,a2能构成等差, 那么a0,a1,a2,a3能构成等差
然后再去考虑如何定义状态,就能相对比较自然地想到用首两项或尾两项表示(应该能叭???)
上面那个博客感觉很赞,代码可参考它
附binary_search函数用法
函数模板:binary_search(arr[],arr[]+size , indx)
参数说明:
arr[]: 数组首地址
size:数组元素个数
indx:需要查找的值
函数功能: 在数组中以二分法检索的方式查找,若在数组(要求数组元素非递减)中查找到indx元素则真,若查找不到则返回值为假。
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<string>
#include<map>
using namespace std;
const int N =5005;
int num[N];
int main()
{
int n;
cin>>n;
for(int i=1;i<=n;++i)
cin>>num[i];
sort(num+1,num+1+n);
int ans=0;
for(int i=1;i<=n;++i)
for(int j=i+1;j<=n;++j)
{
int d=num[j]-num[i];
int cnt=2;
int tmp=num[j]+d;
//while(binary_search(num+j+1,n-j,num[j]+d)) //这样麻烦了,直接找全部的//首地址 元素个数 需要查找的值 找到返回为真,找不到返回为假
while(binary_search(num+1,num+1+n,tmp))
{
tmp+=d;
cnt++; //emm
}
ans=max(cnt,ans);
}
cout<<ans<<endl;
return 0;
}
记录一下看到的很好的启发 51nod1055
对应三个下标
dp[i][j]=max(dp[i][j],dp[pre][i]+1)
此处代表以i,j为最后两项的等差数列(pre找到的时候,pre,i,j可以构成等差数列)
dp的时间复杂度为n^2*nlogn emm怎么感觉有点悬
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<string>
#include<map>
using namespace std;
const int N =5005;
int a[N];
int dp[N][N]; //以i为首项,j为末尾两项的等差数列的长度
int main()
{
int n;
cin>>n;
for(int i=1;i<=n;++i)
cin>>a[i];
sort(a+1,a+1+n);
for(int i=1;i<=n;++i)
{
for(int j=i+1;j<=n;++j)
{
dp[i][j]=2;
}
}
int ans=2;
for(int i=1;i<=n;++i)
for(int j=i+1;j<=n;++j)
{
int d=a[j]-a[i];
int pre=a[i]-d;
int loc=lower_bound(a+1,a+1+n,pre)-a;
if(a[loc]!=pre||loc>=i) continue; //注意我在向前找pre
dp[i][j]=max(dp[i][j],dp[loc][i]+1);
ans=max(ans,dp[i][j]);
}
cout<<ans<<endl;
}