前言
初,遇题甚恐,不知何以解之。一暴以试,得AC,作此篇
分析
- 别学数据结构学傻了
- 我们对于每一个点,可以向左扩展最长能满足条件的区间,然后再向右扩展。但是如果不作些许操作,万一这个序列是10000个1,这样跑就是n^2,直接飞起(但是数据不太强,也可以过)。于是可以记录一个lm[i],rm[i]。
lm[i]:下标i的数向左扩展的最远点的下标 rm[i]:下标i的数向右扩展的最远点的下标
- 原因就是,a|b,b|c,则a|c,就像我们当前求i点向左扩展,找到了j点,且a[j]%a[i]=0。那么满足a[k]%a[j]=0的点也一定满足a[k]%a[i]=0,所以这个时候就可以直接跳到lm[j],然后接着向左找。向右同理。
代码
#include<bits/stdc++.h> using namespace std; const int N=2e6+10; int n; int a[N],l[N],r[N],way[N]; int main() { scanf("%d",&n); for (int i=1;i<=n;i++) scanf("%d",&a[i]); int ans=0; for (int i=1;i<=n;i++) { l[i]=i; for (int j=i-1;j;) { if(a[j]%a[i]) break; l[i]=l[j];j=l[j]-1; } }//向左找 for (int i=n;i>=1;i--) { r[i]=i; for (int j=i+1;j<=n;) { if(a[j]%a[i]) break; r[i]=r[j];j=r[j]+1; } }//向右找 for (int i=1;i<=n;i++) ans=max(ans,r[i]-l[i]); int num=0; for (int i=1;i<=n;i++) if(r[i]-l[i]==ans&&way[num]!=l[i]) way[++num]=l[i]; //这里注意判重 printf("%d\n",num); return 0; }