给出一个序列$ a_1 \dots a_n$。ios
定义一个区间 \([l,r]\) 是好的,当且仅当这个区间中存在一个 \(i\),使得 \(a_i\) 刚好等于 \(a_l, a_{l+1} \ \ \dots \ \ a_{r-1}, a_r\) 的最大公因数。c++
求最长的好的区间的长度。git
第一行 n,表示序列的长度; 第二行 n 个数 a1,a2,...,an。
输出一行一个数,表示最长的好的区间的长度。
乱搞就行,考试的时候睡了一觉就想出来了数组
用\(f[i]\) 表示前面第一个能被\(a[i]\)整除的位置优化
用\(g[i]\) 表示后面第一个能被\(a[i]\)整除的位置ui
则能够递推spa
f[1]=1; for(int i=2;i<=n;++i){ if(a[i]%a[f[i-1]]==0)f[i]=f[i-1]; else f[i]=i; } g[n]=n; for(int i=n-1;i;--i){ if(a[i]%a[g[i+1]]==0)g[i]=g[i+1]; else g[i]=i; }
最后在\(f\)和\(g\)里面连续的一段取最长的就好了code
可是若是有这种数据:ip
5 10 6 6 6 9
咱们写出\(f\)和\(g\):get
f: 1 2 2 2 5 g: 1 4 4 4 5
发现有重复数字时位置会不同
因此再用两个数组\(l[i]\)和\(r[i]\)乱搞一下
for(int i=1;i<=n;++i) r[f[i]]=max(r[f[i]],i), l[g[i]]=min(l[g[i]],i); for(int i=1;i<=n;++i) r[i]=max(r[i],r[f[i]]), l[i]=min(l[i],l[g[i]]); for(int i=1;i<=n;++i)ans=max(ans,r[i]-l[i]+1);
注意卡读入,用fread或者ios和tie优化都行
而后就没有而后了
可能个人思路比较别致
#include<bits/stdc++.h> using namespace std; const int maxn = 4e6+5; #define int long long char getc(){ static char buf[maxn],*p1=buf,*p2=buf; return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,maxn,stdin),p1==p2)? EOF:*p1++; } int mian(){ int s=0,f=1;char ch; while(!isdigit(ch=getc()))(ch=='-')&&(f=-1); for(s=ch-'0';isdigit(ch=getc());s=s*10+ch-'0'); return s*f; } int a[maxn],n,f[maxn],g[maxn],ans,l[maxn],r[maxn]; signed main(){ n=mian(); for(int i=1;i<=n;++i)a[i]=mian(),l[i]=r[i]=i; f[1]=1; for(int i=2;i<=n;++i){ if(a[i]%a[f[i-1]]==0)f[i]=f[i-1]; else f[i]=i; } g[n]=n; for(int i=n-1;i;--i) if(a[i]%a[g[i+1]]==0)g[i]=g[i+1]; else g[i]=i; for(int i=1;i<=n;++i) r[f[i]]=max(r[f[i]],i), l[g[i]]=min(l[g[i]],i); for(int i=1;i<=n;++i){ r[i]=max(r[i],r[f[i]]), l[i]=min(l[i],l[g[i]]); } for(int i=1;i<=n;++i)ans=max(ans,r[i]-l[i]+1); cout<<ans<<endl; return 0; }
让咱们一块儿膜拜大佬@olinr