bzoj 4052: [Cerc2013]Magical GCD

4052: [Cerc2013]Magical GCD

Time Limit: 10 Sec Memory Limit: 128 MB
Submit: 444 Solved: 187
[Submit][Status][Discuss]
Description

给出一个长度在 100 000 以内的正整数序列,大小不超过 10^12。
求一个连续子序列,使得在所有的连续子序列中,它们的GCD值乘以它们的长度最大。
Input

Output

Sample Input

1

5

30 60 20 20 20
Sample Output

80


【分析】
枚举右端点,左端点从枚举点往左扫,这样的话可以得知gcd单调不增。于是用单调栈维护gcd相同时左端点的最小值。


【代码】

//bzoj 4052 [Cerc2013]Magical GCD
#include
#include
#include
#include
#include
#define ll long long
#define M(a) memset(a,0,sizeof a)
#define fo(i,j,k) for(i=j;i<=k;i++)
using namespace std;
const int mxn=1e5+5;
ll n,T,tp,jtp;
ll a[mxn],s[mxn],g[mxn],ss[mxn],gg[mxn];
inline ll read()
{
    ll x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
inline ll gcd(ll x,ll y) {if(x%y==0) return y;return gcd(y,x%y);}
int main()
{
    ll i,j;
    T=read();
    while(T--)
    {
        ll ans=0;tp=1;
        n=read();
        fo(i,1,n) a[i]=read(),ans=max(ans,a[i]);
        s[tp]=1,g[tp]=a[1];
        fo(i,2,n)  //枚举右端点
        {
            ll tmp;jtp=0;
            s[++tp]=i,g[tp]=a[i];  //push
            for(j=tp-1;j;j--) g[j]=gcd(g[j],g[j+1]);  //更新gcd 
            fo(j,1,tp)
              if(g[j]>g[j-1] || j==1)
                ss[++jtp]=s[j],gg[jtp]=g[j];
            tp=jtp;
            fo(j,1,tp)
            {
                s[j]=ss[j],g[j]=gg[j];
                ans=max(ans,g[j]*(i-s[j]+1));
            }
        } 
        printf("%lld\n",ans);
    }
    return 0;
}

你可能感兴趣的:(数论,单调栈)