找最长的等差数列长度
数据范围是 n<=2000,a[i]<=2000
容易想到的是枚举等差数列前两项,得到差值后向后查找
a数组存数值,b数组存某个数出现的个数(也可判断是否出现过)
这是个O(n^3)级别的想法,所以必须在此基础上继续优化
首先排除公差为0的情况,即找出相同的数出现最多次的次数
然后将数列排序后去重,使得剩下的元素两两不相等
这时候就可以开始枚举 i 和 j 两项了
但是从最坏情况考虑,2000项互不相同的测试点时间复杂度仍然是O(n^3),去重没法对这种情况进行优化
所以可以从剪枝入手,在每一次搜索前将可能得到的最大的答案跟目前的答案进行比较
即先把a数组最大的元素存在变量mx中,枚举出 a[i] 后根据 (mx-a[i])/d 来计算可能得到的最大的答案
如果这个值小于等于目前的答案ans,说明这个分支无法对答案做出贡献,就可以直接跳出整个 j 循环
#include<bits/stdc++.h> using namespace std; int a[2050],b[4050]; void solve(){ int n,i,j,k,d,ans=1,mx=0; memset(b,0,sizeof b); cin>>n; for(i=1;i<=n;i++){ cin>>a[i]; ans=max(ans,++b[a[i]]); mx=max(mx,a[i]); } sort(a+1,a+1+n); n=unique(a+1,a+1+n)-a-1; for(i=1;i<n;i++) for(j=i+1;j<=n;j++){ d=a[j]-a[i]; if((mx-a[i])/d<=ans) break; for(k=a[j]+d;b[k];k+=d); ans=max(ans,(k-a[i])/d); } cout<<ans<<' '; } int main(){ ios::sync_with_stdio(0);cin.tie(0);cout.tie(0); int T;cin>>T;for(int t=1;t<=T;t++) solve(); return 0; }