题意:就是找个连续子序列,使得长度乘上这个子序列的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;}
新闻热点
疑难解答