給出一個序列$ 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