BZOJ-4488:最大公约数(GCD)

给定一个长度为 N 的正整数序列Ai对于其任意一个连续的子序列
{Al,Al+1...Ar},我们定义其权值W(L,R )为其长度与序列中所有元素的最大公约数的乘积,即W(L,R) = (R-L+1) ∗ gcd (Al..Ar)。 
JYY 希望找出权值最大的子序列。

Input

输入一行包含一个正整数 N。
接下来一行,包含 N个正整数,表示序列Ai
1 < =  Ai < =  10^12, 1 < =  N < =  100,000

Output

输出文件包含一行一个正整数,表示权值最大的子序列的权值。

Sample Input 5 30 60 20 20 20

Sample Output80 //最佳子序列为最后 4 个元素组成的子序列

题意:求最大的ans=区间长度*区间最大公约数。

思路:我们考虑到gcd的个数是log级别的,我们对于每个gcd,记录第一个位置即可,开始以为是分治求,这是显然可以的。但事实上没有必要,我们从前向后扫描,当扫描到a[i]时,对于之前的所有gcd,用其第一次出现的位置更新一遍答案,同时把每个gcd和a[i]求gcd,如果第一次出现,则记录其对应位置。

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn=100010;
map<ll,int>mp,tp;
map<ll,int>::iterator it;
int main()
{
    int N,i; ll x,ans=0;
    scanf("%d",&N);
    for(i=1;i<=N;i++){
        scanf("%lld",&x); ans=max(ans,x);
        for(it=mp.begin();it!=mp.end();it++){
            ll g=__gcd(x,(*it).first);
            ans=max(ans,(ll)(i-(*it).second+1)*g);
            if(tp.find(g)==tp.end()) tp[g]=(*it).second;
        }
        if(tp.find(x)==tp.end()) tp[x]=i;
        mp=tp; tp.clear();
    }
    printf("%lld\n",ans);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/hua-dong/p/9173757.html