题意:一个长度为n的数列,选一个连续子序列,使得子序列的公约数*长度最大,求这个最大值,n<=1e5。
思路:对于一个数字A,其最多不同的gcd值最多只有logA种
每次向右取一个值时,只要和上一个位置的不同gcd值再取gcd就可得到当前位置的不同gcd值
类似的用到这个性质的有HDU-5869,2016icpc大连网络赛
#include <bits/stdc++.h> using namespace std; typedef long long ll; map<ll,ll> mp; ll n,x,ans; ll gcd(ll x, ll y){ return y==0?x:gcd(y,x%y); } int main(){ int T; scanf("%d",&T); while(T--){ scanf("%lld",&n); mp.clear(); ans=0; for (int i=1; i<=n; i++){//枚举右端点 scanf("%lld",&x); if (!mp.count(x)) mp[x]=i; for (map<ll,ll>::iterator it=mp.begin(); it!=mp.end(); ){ ll tmp=gcd(x,it->first); ans=max(ans,tmp*(i-it->second+1)); if (!mp.count(tmp)) mp[tmp]=it->second; else mp[tmp]=min(mp[tmp],it->second); //tmp不可能大于it->first,只可能tmp<=it->first if (tmp<it->first) mp.erase(it++); else it++; } } printf("%lld\n",ans); } return 0; }