4488: [Jsoi2015]最大公约数
Time Limit: 10 Sec Memory Limit: 256 MBSubmit: 264 Solved: 152
[ Submit][ Status][ Discuss]
Description
给定一个长度为 N 的正整数序列Ai对于其任意一个连续的子序列
{Al,Al+1...Ar},我们定义其权值W(L,R )为其长度与序列中所有元素的最大公约数的乘积,即W(L,R) = (R-L+1) ∗ gcd (Al..Ar)。
JYY 希望找出权值最大的子序列。
Input
输入一行包含一个正整数 N。
接下来一行,包含 N个正整数,表示序列Ai
1 < = Ai < = 10^12, 1 < = N < = 100,000
Output
输出文件包含一行一个正整数,表示权值最大的子序列的权值。
Sample Input
5
30 60 20 20 20
30 60 20 20 20
Sample Output
80
//最佳子序列为最后 4 个元素组成的子序列。
//最佳子序列为最后 4 个元素组成的子序列。
【分析】
有一个知识点:长度n的序列的所有子序列的公约数,最多有logn个。
枚举右端点,那么右端点之前的公约数个数最多logn个。维护这些公约数,每个出现的最左坐标(L)。
扫描所有公约数,取最优解。
【代码】
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e5+5;
int n,a[N];
int dex[N],g[N];
int main()
{
cin>>n;
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
int top=0;
ll ans=0;
for(int i=1;i<=n;i++)
{
dex[++top]=i;
g[top]=a[i];
for(int k=top-1;k>=1;k--)
{
g[k]=__gcd(g[k],g[k+1]);
}
int j=0;
for(int k=1;k<=top;)
{
g[++j]=g[k];
dex[j]=dex[k];
while(g[j]==g[k])k++;
}
top=j;
for(j=1;j<=top;j++)
ans=max(ans,1ll*g[j]*(i-dex[j]+1));
}
cout<<ans<<endl;
}