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;
}

原文地址:https://www.cnblogs.com/kamimxr/p/11295135.html

时间: 2024-10-25 07:59:49

UVA 1642 MagicalGCD 题解的相关文章

UVa 10152 - ShellSort 题解

按他的方法排序,每次移动一个数到顶点,排成需要的序列. Problem D: ShellSort He made each turtle stand on another one's back And he piled them all up in a nine-turtle stack. And then Yertle climbed up. He sat down on the pile. What a wonderful view! He could see 'most a mile! T

UVA 1642 Magical GCD(经典gcd)

题意:给你n(n<=100000)个正整数,求一个连续子序列使序列的所有元素的最大公约数与个数乘积最大 题解:我们知道一个原理就是对于n+1个数与n个数的最大公约数要么相等,要么减小并且减小至少一半(至少少了一个因子) 因此所有子串gcd的总种类数最多只有n*log(a(数字大小))个 我们枚举每个点计算以这个点为结束点的所有后缀,利用dp的思想通过前一次计算的最多log(a)个gcd计算出此时也是最多log(a')个gcd import java.util.Scanner; public cl

[UVA - 12034] Race 题解

此文为博主原创题解,转载时请通知博主,并把原文链接放在正文醒目位置. 题目链接(vjudge):https://vjudge.net/problem/UVA-12034 题目大意: A,B两人赛跑,可能出现三种情况: 1.A,B并列第一 2.A第一,B第二 3.B第一,A第二 现在有N个人赛跑,问可能出现多少种情况,答案对10056取模. 输入格式: 第一行一个数字T(1<=T<=1000),表示数据组数. 接下来T行,每行一个数字N(1<=N<=1000),表示赛跑的人数. 输出

UVA 1642 Magical GCD 暴力+簡單數論

枚舉右端點,往前查找左端點.... 右端點一定的話,最多只有log個不同的gcd值, 用一個數組記錄不同的GCD的值,對每個相同的GCD值記錄一下最靠左的位置... 因爲GCD值不是很多所以 移動右端點時暴力統計即可.. 對與樣例: 30 60 20 20 20 從第1個數座右端點開始枚舉  // (gcd,位置) (30,1) 枚舉以第2個數做爲右端點 (30,1) (60,2) 第3個數 (10,1)  (20,2) .... 後面幾個數都是一樣的... 第5個數 (10,1)  (20,2

UVa 1642 - Magical GCD(数论)

链接: https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=4517 题意: 输入一个n(n≤100000)个元素的正整数序列,求一个连续子序列,使得该序列中所有元素的最大公约数与序列长度的乘积最大.例如,5个元素的序列30, 60, 20, 20, 20的最优解为{60, 20, 20, 20},乘积为gcd(60,20,20,20)*4=8

UVa 1642 Magical GCD (暴力+数论)

题意:给出一个长度在 100 000 以内的正整数序列,大小不超过 10^ 12.求一个连续子序列,使得在所有的连续子序列中, 它们的GCD值乘以它们的长度最大. 析:暴力枚举右端点,然后在枚举左端点时,我们对gcd相同的只保留一个,那就是左端点最小的那个,只有这样才能保证是最大,然后删掉没用的. 代码如下: #pragma comment(linker, "/STACK:1024000000,1024000000") #include <cstdio> #include

UVa 1642 (综合) Magical GCD

题意: 给出一个数列,求一个连续的子序列,使得MGCD(i, j) =  该子序列的长度(j-i+1) × 子序列的gcd 最大,并输出这个最大值. 分析: 感觉可能要用优先队列,但貌似也用不上. 但类似地,从左往右枚举右端点,不难发现随着序列长度的增大,其子序列的最大公约数是非递增的.一般情况下,是呈阶梯状递减的.于是我们只要保留相同的gcd中,左端点最小的那个序列(因为相同的gcd里面它的长度最大,MGCD就是最大的). 右端点更新的时候,同时也要更新每个子序列的gcd,然后把重复的gcd的

UVa 225 Golygons 题解

难度:β 建议用时:40 min 关于这道题目的背景在维基百科上有.很神奇. 但是我们的这道题没有那么多考虑.上来直接东南西北狂搜一通就好了. 算法很简单,直接上过程. 首先确定 "东""南""西""北" 对应的英文字母 "e""s""w""n". 因为题目还说不能后退,所以要把后退的方向也处理出来."东"对"西&qu

紫书第10章存题

UVA 580 枚举出现连续3个U第一次出现的位置.同时需要记录前i位不出现连续3个u的方案. #include <stdio.h> #include <string.h> #include <cmath> #include <algorithm> using namespace std; typedef long long ll; const int maxn = 20 + 10; ll f[maxn],g[maxn]; ll quick(ll a,int