题目大意:给定一个序列,求一个连续子序列,使得序列长度∗gcd最大
题解:丧病的模拟赛题……
固定一个右端点,当左端点向左移动时,[l,r]的gcd单调不增,且每次减小一定为之前的因数,这样gcd不同的位置是log级别的,这样就可以大力暴力了
用一个map维护当gcd=x时能取到的最远左端点
随着右端点的移动,删除不合法的……
我的收获:单调性,少->暴力
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <map>
using namespace std;
#define ll long long
int n,T;
ll x,ans;
map<ll,int> a;
map<ll,int>::iterator it;
ll gcd(ll a,ll b){return !b?a:gcd(b,a%b);}
inline long long read()
{
long long x=0;char c=getchar();
while(c>'9'||c<'0') c=getchar();
while(c>='0'&&c<='9') x=x*10+c-48,c=getchar();
return x;
}
void init()
{
scanf("%d",&n);
a.clear();ans=0;
for(int i=1;i<=n;i++){
x=read();
if(!a.count(x)) a[x]=i;
for(it=a.begin();it!=a.end();){
ll tmp=gcd(x,it->first);
ans=max(ans,tmp*(i-it->second+1));
if(!a.count(tmp)) a[tmp]=it->second;
else a[tmp]=min(a[tmp],it->second);
if(tmp<it->first) a.erase(it++);//必须这样写……
else it++;
}
}
printf("%lld\n",ans);
}
int main()
{
scanf("%d",&T);
while(T--) init();
return 0;
}