传送门:bzoj4052
题解
冷静分析一下求解所有情况的复杂度:
固定区间左端点 l l l, r r r递增的过程中 g c d ( l , r ) gcd(l,r) gcd(l,r)最多变化 l o g log log次。
于是 s t st st表维护区间 g c d gcd gcd,二分变化右端点。
复杂度 O ( n log 2 v a l ) O(n\log^2 val) O(nlog2val)。
代码
#include<stdio.h>
#include<iostream>
#include<math.h>
using namespace std;
const int N=100005;
#define ll long long
int T,n,i,j,x,l,r,mid,Log[N];
ll ans,f[N<<1][20];
inline void read(ll &v){
char ch,fu=0;
for(ch='*'; (ch<'0'||ch>'9')&&ch!='-'; ch=getchar());
if(ch=='-') fu=1, ch=getchar();
for(v=0; ch>='0'&&ch<='9'; ch=getchar()) v=v*10+ch-'0';
if(fu) v=-v;
}
ll gcd(ll a,ll b)
{
if(b==0) return a;else return gcd(b,a%b);
}
ll solve(int l,int r)
{
int x=Log[r-l+1];
return gcd(f[l][x],f[r-(1<<x)+1][x]);
}
int main()
{
scanf("%d",&T);
for(i=1;i<=100000;i++)
Log[i]=log2(i);
while(T--)
{
scanf("%d",&n);
ans=0;
for(i=1;i<=n;i++) read(f[i][0]);
for(j=1;(1<<j)<=n;j++)
for(i=1;i<=n;i++)
f[i][j]=gcd(f[i][j-1],f[i+(1<<j-1)][j-1]);
for(i=1;i<=n;i++)
{
x=i;
while(x<=n)
{
l=x;r=n;
ll s=solve(i,x);
while(l<=r)
{
mid=(l+r)>>1;
if(s==solve(i,mid)) l=mid+1;else r=mid-1;
}
ans=max(ans,solve(i,r)*(r-i+1));
x=l;
}
}
printf("%lld\n",ans);
}
return 0;
}