【BZOJ4052】【Cerc2013】Magical GCD 单调栈

题目大意:给出一个正整数序列,求一个连续子序列,使得这个连续子序列的GCD与长度的乘积最大化,并输出最大值。

首先不难想出N*N的做法(假装GCD是常数):穷举右端点再枚举左端点,然后我们发现如果固定右端点,那么左端点从右往左扫的时候,GCD单调不增,因此可以用单调栈来维护,对于每一个GCD,只记录一个最远的左端点,又因为单调栈中的元素每次改变至少要减少一半,所以元素最多不超过log2(10^12)个,每次右端点移动是维护单调栈并更新答案即可。

/**************************************************************
    Problem: 4052
    User: cqyzhb
    Language: C++
    Result: Accepted
    Time:820 ms
    Memory:7836 kb
****************************************************************/
 
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
#define oo 999999999
#define MAXN 210005
void _read(int &x)
{
    char ch=getchar(); x=0; bool flag=false;
    while(ch<'0' || ch>'9'){if(ch=='-')flag=true; ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0'; ch=getchar();}if(flag)x=-x; return ;
}
void _readLL(long long &x)
{
    char ch=getchar(); x=0; bool flag=false;
    while(ch<'0' || ch>'9'){if(ch=='-')flag=true; ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0'; ch=getchar();}if(flag)x=-x; return ;
}
int N,maxN=0;long long A[MAXN];
void Init()
{
    _read(N);maxN=max(maxN,N);
    for(int i=0;i<=N+1;i++)A[i]=0;
    for(int i=1;i<=N;i++)_readLL(A[i]);
    return ;
}
long long gcd(long long x,long long y)
{
    if(x==0&&y==0)printf("Fuck");
    long long t;
    while(y){t=x%y; x=y; y=t; }
    return x;
}
int sta[MAXN],top,sta_[MAXN],top_;
long long stb[MAXN],stb_[MAXN];
long long ans=0;
void work()
{
    for(int i=1;i<=N;i++)sta[i]=stb[i]=sta_[i]=stb_[i]=0;
    sta[1]=1; top=1; ans=A[1]; stb[1]=A[1];
    for(int i=2;i<=N;i++)
    {
        ans=max(ans,A[i]);
        sta[++top]=i; stb[top]=A[i];
        for(int j=top-1;j>=1;j--)
        {
            stb[j]=gcd(stb[j],stb[j+1]);
        }
        top_=0;
        for(int j=1;j<=top;j++)
        {
            if(stb[j]>stb[j-1] || j==1)
            {
                sta_[++top_]=sta[j]; stb_[top_]=stb[j];
            }
        }
        top=top_;
        for(int j=1;j<=top;j++)
        {
            sta[j]=sta_[j]; stb[j]=stb_[j];
            ans=max(ans,stb[j] * (long long)(i-sta[j]+1));
        }
    }
    //cout<

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