Gym 102082B 二分或DP

时隔一个星期,重新看了这道题。放一下我们组队赛的脑洞:https://blog.csdn.net/iroy33/article/details/88871961

题意:给你一个数组,求用这个数组里面的数字,能构成的等差数列,最大有多长?

DP的思路:

dp[i][j]代表的是以num_{i} 和num_{j} 结尾的等差数列。

如果在a_{i}之前,存在一个数字num_[pre],使得num[i]-num[pre]=num[j]-num[i]=d(d是公差),

那么有递推公式dp[i][j]=max(dp[i][j],dp[pre][i]+1).

中间在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.

哎呀,学弟都是大佬。

 

使用二分的话,就更简单了。

暴力双重循环 i 和 j ,对于num[i] 和num[j],向后找到公差为num[j]-num[i]的数(找的时候,二分查找省时间呗,当然之前先排个序),看有多少个,更新一下结果。



//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;
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值