题意:就是找个连续子序列,使得长度乘上这个子序列的gcd的值最大。
思路:嗯,比较容易想到的就是暴力,每次就是和前一个、前两个.....求gcd乘上长度。
好想的一个优化就是gcd相同的,我们只保留最长的那个序列就可以了。
我们保存[i,j-1]的gcd的数值。以及i这个位置
然后和j去求一个gcd。如果gcd没变。那么这个序列的值不变,最左边还是i,gcd也不变。
如果gcd变小了,那么当前这个序列就要改变,gcd的值改变,i的位置取之前最靠前的一个值。
这样我们每次保存一个最小的i就可以了。
很重要的一点就是随着数量的增加gcd是不断减小的。
然后不断的更新答案就可以了。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
ll a[100005];
map<ll,ll>v;
map<ll,ll>::iterator it,itt;
ll gcd(ll a,ll b)
{
return b?gcd(b,a%b):a;
}
int main()
{
int T,n;
scanf("%d",&T);
while (T--)
{
ll ans=0;
scanf("%d",&n);
v.clear();
for (int i=1; i<=n; i++)
{
scanf("%lld",&a[i]);
ans=max(ans,a[i]);
for (it=v.begin(); it!=v.end(); it++)
{
if(gcd(it->first,a[i])!=it->first)//gcd的值变小了
{
if (!v[gcd(it->first,a[i])])//如果之前没出现过
v[gcd(it->first,a[i])]=it->second;
cout<<v.size()<<endl;
//删除当前的值
itt=it++;
v.erase(itt);
it--;
}
}
if (!v[a[i]])v[a[i]]=i;
cout<<v.size()<<endl;
for (auto it:v)
{
ans=max(ans,(it.first)*(i-it.second+1));
}
}
printf("%lld\n",ans);
}
return 0;
}