bzoj 3357: [Usaco2004]等差数列

Description

    约翰发现奶牛经常排成等差数列的号码.他看到五头牛排成这样的序号:“1,4,3,5,7”
很容易看出“1,3,5,7”是等差数列.
    给出N(1≤N≤2000)数字AI..AN(O≤Ai≤10^9),找出最长的等差数列,输出长度.

Input

    第1行:一个整数N.
    第2到N+1行:每行一个整数Ai,表示牛的号码.

Output

 
    最长等差数列的长度.

Sample Input

5
1
4
3
5
7

Sample Output

4

HINT

Source

Green



只能想到n^2logn的。勉强可以卡过去
f[i][j]表示结尾为i公差为j的答案
然后我们枚举1到i-1然后转移就可以了。
P.S 当n=1时,ans=1
#include<map>
#include<cstdio>
#include<algorithm>
using namespace std;
map<int,int> f[2001];
int a[2001];
int main()
{
     int n;
     scanf("%d",&n);
     int i,j;
     for(i=1;i<=n;i++)
          scanf("%d",&a[i]);
     //sort(a+1,a+1+n);
     if(n==1)
     {
          printf("1\n");
          return 0;
     }
     int ans=0;
     for(i=1;i<=n;i++)
     {
          for(j=1;j<i;j++)
          {
               f[i][a[i]-a[j]]=max(max(f[i][a[i]-a[j]],f[j][a[i]-a[j]]+1),2);
              // printf("%d %d %d\n",i,a[i]-a[j],f[i][a[i]-a[j]]);
               ans=max(f[i][a[i]-a[j]],ans);
          }
     }
     printf("%d\n",ans);
     return 0;
}

 写了个O(n^2)的一直没来及更新= =f[i][j]枚举第j个为结尾前一个为第i个就可以了。然后把所有的数手写hash
#include<cstdio>
#include<algorithm>
using namespace std;
int a[2001];
struct number
{
     int x,t;
     bool operator <(number y) const
     {
          return x<y.x;
     }
}b[2001];
int sx[2001],fx[2001],la[100001];
int f[2001][2001],d[2001][2001];
struct hash
{
     int x,t;
}ha[10000011];
int mod=10000007;
inline void phash(int x,int px)
{
     int t=x%mod;
     while(ha[t].x!=x&&ha[t].t!=0)
          t=(t+1)%mod;
     if(ha[t].x==0)
     {
          ha[t].x=x;
          ha[t].t=px;
     }
}
inline int fhash(int x)
{
     int t=x%mod;
     while(ha[t].x!=x&&ha[t].t!=0)
          t=(t+1)%mod;
     if(ha[t].t==0)
          return -1;
     return ha[t].t;
}
int main()
{
//	 freopen("arithprg.in","r",stdin);
//	 freopen("arithprg.out","w",stdout);
     int n;
     scanf("%d",&n);
     if(n==1)
     {
          printf("1\n");
          return 0;
     }
     int i,j;
     for(i=1;i<=n;i++)
     {
          scanf("%d",&a[i]);
          b[i].x=a[i];
          b[i].t=i;
     }
     sort(b+1,b+1+n);
     int p=0;
     b[0].x=-1;
     for(i=1;i<=n;i++)
     {
          if(b[i].x!=b[i-1].x)
          {
               p++;
               sx[p]=b[i].x;
               phash(b[i].x,p);
          }
          fx[b[i].t]=p;
     }
     for(i=1;i<=n;i++)
     {
          for(j=i+1;j<=n;j++)
          {
          	   if(a[i]-(a[j]-a[i])<0)
          	        continue;
          	   int loc=fhash(a[i]-(a[j]-a[i]));
          	   if(loc==-1)
          	        continue;
               d[i][j]=la[loc];
          }
          la[fx[i]]=i;
     }
     int ans=0;
	 for(i=1;i<=n;i++)
     {
          for(j=1;j<=i-1;j++)
          {
               f[j][i]=max(f[d[j][i]][j]+1,2);
               ans=max(f[j][i],ans);
          }
     }
     printf("%d\n",ans);
     return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值