正题
题目链接:https://www.luogu.com.cn/problem/P5502
题目大意
nnn个数,求一个L,RL,RL,R使得最大化(R−L+1)∗gcd(aL,aL+1,aL+1...aR−1,aR)(R-L+1)*gcd(a_L,a_{L+1},a_{L+1}...a_{R-1},a_R)(R−L+1)∗gcd(aL,aL+1,aL+1...aR−1,aR)
解题思路
考虑分治,答案分为两种可能
- 在l∼midl\sim midl∼mid或mid+1∼rmid+1\sim rmid+1∼r中,分治下去求即可
- LLL在l∼midl\sim midl∼mid中,RRR在mid+1∼rmid+1\sim rmid+1∼r中,此时考虑如何计算这个东西
显然amida_{mid}amid是一定要在答案中的,而如果目前的gcdgcdgcd为www,且左右端点扩展可以使得www不变时那么就一定是扩展的最优,所以我们每次都扩展到无法再扩展时更新答案。无法扩展时我们有两种扩展方法,一种是左端点向左,一种是右端点向右,我们分两次一次往左一次往右即可。
时间复杂度O(nlognlogai)O(n\log n\log a_i)O(nlognlogai)
codecodecode
#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
const ll N=1e5+10;
ll n,a[N],ans;
void solve(ll l,ll r){if(l==r)return;ll mid=(l+r)>>1;solve(l,mid);solve(mid+1,r);ll L=mid,R=mid,w=a[mid];while(l<=L&&R<=r){while(l<L&&__gcd(w,a[L-1])==w)L--;while(R<r&&__gcd(w,a[R+1])==w)R++;ans=max(ans,(R-L+1)*w);if(l<L)w=__gcd(w,a[--L]);else break;}L=mid,R=mid,w=a[mid];while(l<=L&&R<=r){while(l<L&&__gcd(w,a[L-1])==w)L--;while(R<r&&__gcd(w,a[R+1])==w)R++;ans=max(ans,(R-L+1)*w);if(R<r)w=__gcd(w,a[++R]);else break;}return;
}
int main()
{scanf("%lld",&n);for(ll i=1;i<=n;i++)scanf("%lld",&a[i]);solve(1,n);printf("%lld",ans);
}