BZOJ4488 JSOI2015最大公约数

  显然若右端点确定,gcd最多变化log次。容易想到对每一种gcd二分找最远端点,但这样就变成log^3了。注意到右端点右移时,只会造成一些gcd区间的合并,原本gcd相同的区间不可能分裂。由于区间只有log个,暴力即可。

#include<iostream> 
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;
#define N 100010
#define ll long long
ll read()
{
    ll x=0,f=1;char c=getchar();
    while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
    while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
    return x*f;
}
int n,r[N],tmp[N],head=1,tail;
ll a[N],ans,g[N];
ll gcd(ll n,ll m){return m==0?n:gcd(m,n%m);}
int main()
{
#ifndef ONLINE_JUDGE
    freopen("bzoj4488.in","r",stdin);
    freopen("bzoj4488.out","w",stdout);
    const char LL[]="%I64d\n";
#else
    const char LL[]="%lld\n";
#endif
    n=read();
    for (int i=1;i<=n;i++) a[i]=read();
    for (int i=1;i<=n;i++)
    {
        r[++tail]=i;g[tail]=a[i];
        for (int j=head;j<tail;j++) g[j]=gcd(g[j],a[i]);
        int x=tail+1;
        for (int j=tail;j>=head;j--)
        {
            int t=j;
            while (t>head&&g[t-1]==g[j]) t--;
            x--,r[x]=r[t],g[x]=g[t];
            j=t;
        }
        head=x;
        for (int j=head;j<=tail;j++) ans=max(ans,(i-r[j]+1)*g[j]);
    }
    cout<<ans;
    return 0;
}

 

posted @ 2018-10-31 00:46  Gloid  阅读(134)  评论(0编辑  收藏  举报