ZJNU 2220

找最长的等差数列长度

数据范围是 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;
}
原文地址:https://www.cnblogs.com/stelayuri/p/12409846.html