1056 最长等差数列 V2

1056 最长等差数列 V2

基准时间限制:8 秒 空间限制:131072 KB

Description

N个不同的正整数,从中选出一些数组成等差数列。
例如:1 3 5 6 8 9 10 12 13 14
等差子数列包括(仅包括两项的不列举)
1 3 5
1 5 9 13
3 6 9 12
3 8 13
5 9 13
6 8 10 12 14
其中6 8 10 12 14最长,长度为5。
现在给出N个数,你来从中找出一个长度 >= 200 的等差数列,如果没有,输出No Solution,如果存在多个,输出最长的那个的长度。

Input

第1行:N,N为正整数的数量(1000 <= N <= 50000)。
第2 - N+1行:N个正整数。(2<= A[i] <= 10^9)
(注,真实数据中N >= 1000,输入范例并不符合这个条件,只是一个输入格式的描述)

Output

找出一个长度 >= 200 的等差数列,如果没有,输出No Solution,如果存在多个,输出最长的那个的长度。

Input示例

10
1
3
5
6
8
9
10
12
13
14

Output示例

No Solution

Solution

显然这道题不能用常规方法n^3,虽说时间复杂度有8s,但n^3还是会炸,首先,通过枚举两个数确定公差是必须的,所以说n^2一定存在,而对于判断这个数列的长度,则可以采取hash的玄学优化,虽然看似这样还是n^3的,不过却可以跑得飞快(当然你也可以加个排序来剪枝)
#include<cstdio>
#include<algorithm>
#include<cmath>
#define inf 1000000000
#define Mod 10000000
using namespace std;
int mx,mn,ans=0,n;
int x[50010],hash[Mod];
int read(){
    int ans=0;
    char ch=getchar();
    while(ch<'0'||ch>'9')ch=getchar();
    while(ch>='0'&&ch<='9')ans=ans*10+ch-'0',ch=getchar();
    return ans;
}
int calc(int x){
    int now=x%Mod;
    if (!now) now+=Mod;
    while (hash[now]!=0 && hash[now]!=x) now=now%Mod+1;
    return now;
}
bool find(int x){
    if (hash[calc(x)]==x) return 1;
    return 0;
}
int main(){
    mx=0,mn=inf;
    n=read();
    for (int i=1;i<=n;i++){
        x[i]=read();
        if (x[i]>mx) mx=x[i];
        if (x[i]<mn) mn=x[i];
    }
    ans=199;
    sort(x+1,x+n+1);
    x[0]=x[1]-1;
    for (int i=1;i<=n;i++)
        hash[calc(x[i])]=x[i];
    for (int i=1;i<=n;i++)
        for (int j=i+1;j<=n;j++){
            int y=x[j]-x[i],k=x[j],len=2;;
            if ((long long)x[i]+ans*y>mx || (long long)x[i]+ans*y<mn) break;
            while (1){
                if (!find(k+y)) break;
                k+=y;
                len++;
            }
            if (len>ans) ans=len;
        }
    if (ans<200) printf("No Solution"); else printf("%d\n",ans);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值