牛客網NOIP賽前集訓營-提升組(第四場)B區間

牛客網NOIP賽前集訓營-提升組(第四場)B區間

題目描述

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

相關文章
相關標籤/搜索