luogu P5502 [JSOI2015]最大公约数|st表+二分
作者:互联网
题目描述
给定一个长度为 \(N\) 的正整数序列 \(A_i\) 。
对于其任意一个连续的子序列 \(A_l,A_{l+1},...,A_r\) ,我们定义其权值 \(W(L,R)\) 为其长度与序列中所有元素的最大公约数的乘积,即 \(W(L,R) = (R-L+1) × \gcd (A_l,...,A_r)\)。
JYY 希望找出权值最大的子序列。
输入格式
输入一行包含一个正整数 \(N\) 。
接下来一行,包含 \(N\) 个正整数,表示序列 \(A_i\) 。
输出格式
输出文件包含一行一个正整数,表示权值最大的子序列的权值。
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
using namespace std;
#define int long long
const int N=1e5+5;
int n,a[N],st[N][21],logN[N];
int gcd(int a,int b){
if(b==0)return a;
return gcd(b,a%b);
}
inline int getgcd(int l,int r){
int s=logN[r-l+1];
return gcd(st[l][s],st[r-(1<<s)+1][s]);
}
signed main(){
cin>>n;
int ans=0;
logN[0]=-1;
for(int i=1;i<=n;i++){
scanf("%lld",&a[i]);
st[i][0]=a[i];
logN[i]=logN[i>>1]+1;
ans=max(ans,a[i]);
}
for(int j=1;j<=logN[n];j++)
for(int i=1;i+(1<<j)-1<=n;i++)
st[i][j]=gcd(st[i][j-1],st[i+(1<<(j-1))][j-1]);
for(int i=1,l,r,mid,lst,res;i<=n;i++){
res=a[i],lst=i;
while(1){
l=lst,r=n;
while(l<=r){
mid=(l+r)>>1;
if(res==getgcd(i,mid))l=mid+1;
else r=mid-1;
}
ans=max(ans,(l-i)*res);
if(l>n)break;
res=getgcd(i,l);
lst=l;
}
}
cout<<ans<<endl;
}
标签:JSOI2015,int,luogu,P5502,st,ans,序列,include,gcd 来源: https://www.cnblogs.com/naruto-mzx/p/15931343.html