找最长的等差数列长度
数据范围是 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 来计算可能得到的最大的答案
扫描二维码关注公众号,回复:
9577672 查看本文章
如果这个值小于等于目前的答案ans,说明这个分支无法对答案做出贡献,就可以直接跳出整个 j 循环
1 #include<bits/stdc++.h> 2 using namespace std; 3 int a[2050],b[4050]; 4 void solve(){ 5 int n,i,j,k,d,ans=1,mx=0; 6 memset(b,0,sizeof b); 7 cin>>n; 8 for(i=1;i<=n;i++){ 9 cin>>a[i]; 10 ans=max(ans,++b[a[i]]); 11 mx=max(mx,a[i]); 12 } 13 sort(a+1,a+1+n); 14 n=unique(a+1,a+1+n)-a-1; 15 for(i=1;i<n;i++) 16 for(j=i+1;j<=n;j++){ 17 d=a[j]-a[i]; 18 if((mx-a[i])/d<=ans) 19 break; 20 for(k=a[j]+d;b[k];k+=d); 21 ans=max(ans,(k-a[i])/d); 22 } 23 cout<<ans<<'\n'; 24 } 25 int main(){ 26 ios::sync_with_stdio(0);cin.tie(0);cout.tie(0); 27 int T;cin>>T;for(int t=1;t<=T;t++) 28 solve(); 29 return 0; 30 }