【BZOJ4052】【Cerc2013】Magical GCD 单调栈

来源:互联网 发布:网络十大作家排行榜 编辑:程序博客网 时间:2024/04/28 11:14

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

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

/**************************************************************    Problem: 4052    User: cqyzhb    Language: C++    Result: Accepted    Time:820 ms    Memory:7836 kb****************************************************************/ #include<cstdlib>#include<cstdio>#include<iostream>#include<cstring>#include<cmath>#include<algorithm>#include<queue>#include<vector>using namespace std;#define oo 999999999#define MAXN 210005void _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<<ans<<endl;    printf("%lld\n",ans);    return ;}int main(){//    freopen("c1.in","r",stdin); //   freopen("out.txt","w",stdout);    int t;scanf("%d",&t);    while(t--)    {        Init();        work();    }//    printf("%d",maxN);    return 0;}

0 0
原创粉丝点击