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 class Main{

    static int Max=100010;
    static Long[] num=new Long[Max];
    static Long[][] gcd=new Long[Max][100];//后缀的gcd值只可能有loga种
    static int[][] len=new int[Max][100];//对应位置的长度

    public static Long Gcd(Long i,Long j) {
        if(j==0)
            return i;
        else
            return Gcd(j, i%j);
    }

    public static void main(String[] args) {
        int t,n;
        Scanner sc=new Scanner(System.in);
        t=sc.nextInt();
        while(t!=0){
            n=sc.nextInt();
            for(int i=0;i<n;++i){
                num[i]=sc.nextLong();
            }
            System.out.println(SolveGcd(n));
            t--;
        }
    }

    private static Long SolveGcd(int n) {
        Long res=0L;
        int coun,pre=0;
        //从第一个开始计算后缀
        for(int i=0;i<n;++i){

            coun=0;
            gcd[i][coun]=num[i];
            len[i][coun]=1;
            res=Math.max(res,num[i]);
            coun++;

            //使用上一层后缀计算此层,并且注意删除相同的值
            for(int j=0;j<pre;++j){
                gcd[i][coun]=Gcd(num[i], gcd[i-1][j]);
                len[i][coun]=len[i-1][j]+1;
                res=Math.max(res, gcd[i][coun]*len[i][coun]);
                if(gcd[i][coun].equals(gcd[i][coun-1])){//gcd相同时存总个数
                    len[i][coun-1]=len[i][coun];
                }else{
                    coun++;
                }
            }
            pre=coun;
        }
        return res;
    }
}
时间: 2024-08-29 02:33:05

UVA 1642 Magical GCD(经典gcd)的相关文章

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

hdoj 2504 又见GCD 【GCD判定】

思路:一个一个的找,因为c不等于b 且b是(a, c)的最大公约数, 所以c是b的整数倍, 每找到一个c就判断与 a的最大公约数是不是b,不是的话,就继续 刚开始的时候 居然把gcd非递归形式忘了...也没想用递归形式.. 又见GCD Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 10151    Accepted Submissio

UESTC 923 稳住GCD DP + GCD

定义:dp[i][j] 表示 在前i个数中,使整个gcd值为j时最少取的数个数. 则有方程: gg = gcd(a[i],j) gg == j : 添加这个数gcd不变,不添加,  dp[i][j] = dp[i-1][j] gg != j: t添加,更新答案,                dp[i][gg] = dp[i-1][j] + 1 最后答案为dp[n][g] (g为原始的所有数的gcd) 时间复杂度: O(n*max(a[i])) 代码: #include <iostream>

HDU 5726 GCD 区间GCD=k的个数

GCD Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 2742    Accepted Submission(s): 980 Problem Description Give you a sequence of N(N≤100,000) integers : a1,...,an(0<ai≤1000,000,000). There ar

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个值发生改变

UVa 1642 (综合) Magical GCD

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

UVa 11426 (欧拉函数 GCD之和) GCD - Extreme (II)

题意: 求sum{gcd(i, j) | 1 ≤ i < j ≤ n} 分析: 有这样一个很有用的结论:gcd(x, n) = i的充要条件是gcd(x/i, n/i) = 1,因此满足条件的x有phi(n/i)个,其中Phi为欧拉函数. 所以枚举i和i的倍数n,累加i * phi(n/i)即可. 1 #include <cstdio> 2 typedef long long LL; 3 4 const int maxn = 4000000; 5 6 int phi[maxn + 10]