luogu P7009 [CERC2013] Magical GCD|st表+二分

\(T\) 组询问,每次给出 \(n\) 个数 \(a_i\)

你需要找到这个数组的一个子序列(要求编号连续),使得该序列中所有数的最大公约数和序列长度的乘积最大,并输出这个最大值

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define int long long
const int N=1e5+5;
int n,a[N],st[N][21],logN[N];
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(){
	int T; cin>>T;
	while(T--){
		scanf("%lld",&n);
		logN[0]=-1;
		int sum=0;
		for(int i=1;i<=n;i++){
			scanf("%lld",&a[i]);
			st[i][0]=a[i];
			logN[i]=logN[i>>1]+1;
			sum=max(sum,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;i<=n;i++){
			int l,r,res=a[i],mid,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;
				}
				sum=max(sum,(l-i)*res);
				if(l==n+1)break;
				lst=l;
				res=getgcd(i,l);
			}	
		}
		printf("%lld\n",sum);
	}
}
posted @ 2022-02-23 11:22  白木偶君  阅读(25)  评论(0编辑  收藏  举报