【bzoj4488: [Jsoi2015]最大公约数】性质题

4488: [Jsoi2015]最大公约数

Time Limit: 10 Sec   Memory Limit: 256 MB
Submit: 242   Solved: 141
[ 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

Sample Output

80
//最佳子序列为最后 4 个元素组成的子序列。


开始想着怎么在log的时间里弄出所有(l,r)的gcd的值。

后来查了题解,发现说有一个性质:gcd的个数不会超过log(n),那就直接暴力了。

每次把一个数和之前所有的gcd再求一次gcd,把重复的删去,再把这个数加到末尾,直到做完。

#include<cstdio>
#include<algorithm>
#include<iostream>
#define N 200005
#define ll long long
using namespace std;
ll a[N],p[2][N],ans;
int n,k,cnt[N],len[2][N];
bool cmp(ll a,ll b){
	return a<b;
}
ll gcd(ll a,ll b){
	ll r=a%b;
	while(r){
		a=b;b=r;r=a%b;
	}
	return b;
}
int main(){
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
		scanf("%lld",&a[i]);
	k=1;
	p[k][1]=a[1];cnt[k]=1;len[k][1]=1;ans=a[1];
	for(int i=2;i<=n;i++){
		for(int j=1;j<=cnt[k];j++)
			p[k][j]=gcd(p[k][j],a[i]);
		sort(p[k]+1,p[k]+1+cnt[k],cmp);
		cnt[k^1]=0;p[k][0]=-1;
		for(int j=1;j<=cnt[k];j++){
				if(p[k][j]!=p[k][j-1]){
					cnt[k^1]++;
					len[k^1][cnt[k^1]]=len[k][j]+1;
					p[k^1][cnt[k^1]]=p[k][j];
				}
				else len[k^1][cnt[k^1]]=max(len[k^1][cnt[k^1]],len[k][j]+1);
				ans=max(ans,len[k^1][cnt[k^1]]*p[k^1][cnt[k^1]]);
			}
		cnt[k^1]++;p[k^1][cnt[k^1]]=a[i];
		len[k^1][cnt[k^1]]=1;
		ans=max(ans,a[i]);
		k^=1;
	}
	printf("%lld\n",ans);
}


©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页