您的位置:首页 > 其它

【BZOJ4052】【Cerc2013】Magical GCD 单调栈

2016-06-04 09:10 579 查看
题目大意:给出一个正整数序列,求一个连续子序列,使得这个连续子序列的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 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<<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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: