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的子序列的gcd最多有logn个,则可直接枚举右端点r,同时用数组g维护从1到r的所有gcd,去掉重复,同时用数组indx记录每个gcd出现的位置的左端点l,记录最大的ans即可。
#include<stdio.h>
#include <algorithm>
#include<iostream>
#include<string.h>
#include<vector>
#include<stdlib.h>
#include<math.h>
#include<queue>
#include<deque>
#include<ctype.h>
#include<map>
#include<set>
#include<stack>
#include<string>
#include<algorithm>
#define INF 0x3f3f3f3f
#define gcd(a,b) __gcd(a,b)
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define FAST_IO ios::sync_with_stdio(false)
const double PI = acos(-1.0);
const double eps = 1e-6;
const int MAX=1e5+10;
const int mod=1e9+7;
typedef long long ll;
using namespace std;
inline ll lcm(ll a,ll b){return a/gcd(a,b)*b;}
inline ll qpow(ll a,ll b){ll r=1,t=a; while(b){if(b&1)r=(r*t)%mod;b>>=1;t=(t*t)%mod;}return r;}
inline ll inv1(ll b){return qpow(b,mod-2);}
inline ll exgcd(ll a,ll b,ll &x,ll &y){if(!b){x=1;y=0;return a;}ll r=exgcd(b,a%b,y,x);y-=(a/b)*x;return r;}
inline ll read(){ll x=0,f=1;char c=getchar();for(;!isdigit(c);c=getchar()) if(c=='-') f=-1;for(;isdigit(c);c=getchar()) x=x*10+c-'0';return x*f;}
const int N=1e5+5;
int indx[N],g[N];
int main()
{
int n;
cin>>n;
ll ans=0;
int top=0;
for(int i=1;i<=n;i++)
{
indx[++top]=i;
scanf("%d",&g[top]);
for(int j=top-1;j>=1;j--)
g[j]=gcd(g[j],g[j+1]);
int k=0;
for(int j=1;j<=top;)
{
g[++k]=g[j];
indx[k]=indx[j];
while(g[k]==g[j]) j++;
}
top=k;
for(int j=1;j<=top;j++)
ans=max(ans,1ll*g[j]*(i-indx[j]+1));
}
printf("%lld\n",ans);
return 0;
}