Gym - 102082B Arithmetic Progressions

题意:给定一组数,求能组成的最长的等差数列是多少?

看到有人说这是一个模板题,(ΩДΩ),刷题刷太少了嘛_(:з」∠)_

和队友想到一个蛇皮的状态定义和转移方程,一直wa在test 11,感谢roMxx提供的样例

定义dp[i][j]=x表示num[j]为以num[i]为首项的第j项,t是由此计算出的公差

dp[i][mp[num[j]+(int)t]] = dp[i][j] + 1;

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

a_2-a_1=a_3-a_2对应三个下标pre.i,j dp[i][j]=max(dp[i][j],dp[pre][i]+1)

 此处dp[i][j]代表以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;
}

 

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值