UVA 1642 MagicalGCD 题解

Posted kamimxr

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了UVA 1642 MagicalGCD 题解相关的知识,希望对你有一定的参考价值。

题面

本题是一道区间最大公约数的模板题;

 

如果N^2暴力的话当然会超时,所以我们要发掘出区间gcd的特点;

设gcd[i]表示区间[1,i]的最大公约数;

我们可以发现,从一个点i到1之间的所有区间的gcd均满足gcd[j]=GCD(gcd[j-1],a[j]);

由于gcd的性质,所以gcd[]是单调不增的;

接着,我们似乎发现了一个更神奇的事情,g[]中不同的值最多有log(max(a[i]))个;

换句话说,虽然g[]数组的长度为n,但在以上两个条件的限制下,最多仅仅有logA个值发生改变的地方;

所以我们遍历一遍右端点,处理出每个i到j(0<=i<=j)的区间的最大公约数;

注意,这并不再是n^2了,因为从i到j在long long 范围内最多有64个不同的值,所以我们只要遍历一遍这些点i就可以知道所有的0<=i<=j到j的区间的gcd;

神奇吧?

综上所述,求出所有区间的gcd仅仅需要nlogA的时间,完全可以切掉这道题;

 

 

#include <bits/stdc++.h>
#pragma GCC optimize(3)
#define ll long long
using namespace std;
int n;
long long a[100010];
long long gcd(long long a,long long b)

    if(b==0) return a;
    return gcd(b,a%b);

vector<pair<long long ,long long> > vec[100010]; //第一维是值,第二维是在枚举右端点所用的点的编号
int main ()

    cin>>n;
    for(register int i=1;i<=n;i++)
        scanf("%lld",&a[i]);
    
    for(register int i=1;i<=n;i++)
        long long x=a[i],y=i;        
        vec[i].push_back(make_pair(x,y));        
        for(register int j=0;j<vec[i-1].size();j++)
            if(x==1) break;
            long long GCD=gcd(x,vec[i-1][j].first);    
            if(GCD!=x)
                x=GCD;
                y=vec[i-1][j].second;
                vec[i].push_back(make_pair(x,y));
            
        
    
    long long ans=0;
    for(register int i=1;i<=n;i++)
        int w=vec[i].size()-1;
        for(register int j=0;j<w;j++)
            pair<long long,long long> p1=vec[i][j];
            pair<long long,long long> p2=vec[i][j+1];
            ans=max(ans,p1.first*(i-p2.second)); //注意,i-p2.second却不加1的原因是因为该区间其实是[p2.second,i-1];
        
        ans=max(ans,vec[i][vec[i].size()-1].first*i);
    
    cout<<ans;

 

以上是关于UVA 1642 MagicalGCD 题解的主要内容,如果未能解决你的问题,请参考以下文章

题解Street Numbers [UVA138]

UVa 1642 - Magical GCD(数论)

题解Puzzle [Uva1399]

UVA540 Team Queue——题解 by hyl天梦

UVa 1642 Magical GCD (暴力+数论)

UVA 11729 Commando War 题解