4052: [Cerc2013]Magical GCD

4052: [Cerc2013]Magical GCD

Time Limit: 10 Sec  Memory Limit: 128 MB
Submit: 148  Solved: 70
[Submit][Status][Discuss]

Description

给出一个长度在 100 000 以内的正整数序列,大小不超过 10^12。

求一个连续子序列,使得在所有的连续子序列中,它们的GCD值乘以它们的长度最大。

Input

Output

Sample Input



30 60 20 20 20

Sample Output

80

HINT

Source

题解:我会说这题暴力就水过了?= =实际上此题应该采用的方法也差不多就是暴力= =

很明显,当我们从后往前一路求最大公约数时,最多不会超过logN种(HansBug:因为要么就不变,要变就得至少少一半^_^),所以只需要记录下哪些地方可能引起公因数变化即可——

具体方法:求出两两相邻的两数的最大公约数,然后将所有的前一个公因数不是后一个的倍数的位置记录下来,后面专门留意这些位置即可(HansBug:很明显,要是前者是后者的倍数的话,那么既然都是后面的因数,则必然是前面的因数,不可能引起变化,所以记录下这些就够了,之所以不直接把原数列这么干是因为事实证明两两求下之后的数列突然变得异常优美,想想为什么^_^)

还有个萌萌哒优化:当当前的最大公因数即使到数列最前面都难以超越当前最大值的话,就可以跳掉了

(如上是对比,上面的无优化的,下面的是优化的,事实证明快了不是一点= =)

 1 /**************************************************************
 2     Problem: 4052
 3     User: HansBug
 4     Language: Pascal
 5     Result: Accepted
 6     Time:1644 ms
 7     Memory:2180 kb
 8 ****************************************************************/
 9
10 var
11    i,j,k,l,m,n,t:longint;
12    ans,v:int64;
13    a,b:array[0..100005] of int64;
14    c:array[0..100005] of longint;
15 function gcd(x,y:int64):int64;inline;
16          var z:int64;
17          begin
18               while y<>0 do
19                     begin
20                          z:=x mod y;
21                          x:=y;
22                          y:=z;
23                     end;
24               exit(x);
25          end;
26 begin
27      readln(t);
28      while t>0 do
29            begin
30                 readln(n);ans:=0;m:=1;c[1]:=1;
31                 for i:=1 to n do
32                     begin
33                          read(a[i]);
34                          if a[i]>ans then ans:=a[i];
35                     end;
36                 readln;
37                 for i:=1 to n-1 do b[i]:=gcd(a[i],a[i+1]);
38                 for i:=1 to n-2 do
39                     if (b[i] mod b[i+1])<>0 then
40                        begin
41                             inc(m);c[m]:=i+1;
42                        end;
43                 c[m+1]:=maxlongint;c[0]:=-1;
44                 l:=0;
45                 for i:=1 to n-1 do
46                     begin
47                          while c[l]<=i do inc(l);
48                          dec(l);v:=b[i];
49                          for j:=l downto 1 do
50                              begin
51                                   if int64(int64(i-c[j]+2)*v)>ans then ans:=(int64(i-c[j]+2)*v);
52                                   v:=gcd(v,b[c[j]-1]);
53                                   if int64(int64(i+1)*v)<=ans then break;
54                                   if v=1 then
55                                      begin
56                                           if (i+1)>ans then ans:=i+1;
57                                           break;
58                                      end;
59                              end;
60                     end;
61                 writeln(ans);
62                 dec(t);
63            end;
64      readln;
65 end.
时间: 2024-11-06 13:59:26

4052: [Cerc2013]Magical GCD的相关文章

bzoj 4052: [Cerc2013]Magical GCD

bzoj4488的双倍经验!! 1 #include <bits/stdc++.h> 2 #define LL long long 3 using namespace std; 4 inline LL ra() 5 { 6 LL x=0; char ch=getchar(); 7 while (ch<'0' || ch>'9') ch=getchar(); 8 while (ch>='0' && ch<='9') {x=x*10+ch-'0';ch=ge

【BZOJ4052】[Cerc2013]Magical GCD 乱搞

[BZOJ4052][Cerc2013]Magical GCD Description 给出一个长度在 100 000 以内的正整数序列,大小不超过 10^12. 求一个连续子序列,使得在所有的连续子序列中,它们的GCD值乘以它们的长度最大. Sample Input 1 5 30 60 20 20 20 Sample Output 80 题解:先思考暴力的做法.我们从一个数开始往左扫,将所有使得gcd改变的位置都记录下来.由于gcd的每次改变都至少/2,所以这样的位置不超过log个. 那么我们

[Cerc2013]Magical GCD

https://vjudge.net/problem/UVA-1642 题意:在一个序列中,找出一段连续的序列,使得长度*gcd最大 固定右端点,当左端点从左向右移动时,gcd不变或变大 gcd相同时,序列越长越好 所以相同的gcd只记录最靠左的位置 当右端点由r转移向r+1时 重新计算gcd,然后去重 gcd最多只会有log个 #include<cstdio> #include<iostream> #include<algorithm> #define N 10000

[BZOJ4052][Cerc2013]Magical GCD

试题描述 给出一个长度在 100 000 以内的正整数序列,大小不超过 10^12. 求一个连续子序列,使得在所有的连续子序列中,它们的GCD值乘以它们的长度最大. 输入 本题为多组数据. 第一行一个整数 T,表示数据组数. 每组数据第一行为一个整数 n,表示序列长度:第二行为 n 个整数表示序列. 输出 对于每组数据,输出 max{ gcd * length } 输入示例 1 5 30 60 20 20 20 输出示例 80 数据规模及约定 见"试题描述" 题解 可以发现,随着子序列

【数论】【暴力】bzoj4052 [Cerc2013]Magical GCD

考虑向一个集合里添加一个数,它们的gcd要么不变,要么变成原gcd的一个约数.因此不同的gcd只有log个. 所以对于每个位置,维护一个表,存储从这个位置向前所有的不同的gcd及其初始位置,然后暴力更新答案,反正这个表不会很长. #include<cstdio> #include<algorithm> #include<cstring> using namespace std; #define N 100001 typedef long long ll; typedef

【bzoj4052】[Cerc2013]Magical GCD 暴力

题目描述 给出一个长度在 100 000 以内的正整数序列,大小不超过 10^12. 求一个连续子序列,使得在所有的连续子序列中,它们的GCD值乘以它们的长度最大. 样例输入 1 5 30 60 20 20 20 样例输出 80 题解 暴力 由于$\gcd$具有结合律,所以如果$\gcd(a,b)$比$a$小,那么至少小了一半. 所以所有以一个数为右端点的区间中,本质不同的$\gcd$个数只有$\log a$个. 于是从左向右枚举右端点,统计出以该点为右端点的所有$\gcd$以及区间长度,统计答

【BZOJ】【4052】【CERC2013】Magical GCD

DP/GCD 然而蒟蒻并不会做…… Orz @lct1999神犇 首先我们肯定是要枚举下端点的……嗯就枚举右端点吧…… 那么对于不同的GCD,对应的左端点最多有log(a[i])个:因为每次gcd缩小,至少变成gcd/2(2是最小的质因数),所以是log个左端点…… 所以我们就有了log段!每段的gcd是相同的.当我们加入一个新的右端点时,除了该节点本身外,不会出现新的左端点,原有的左端点可能会不变,或是两(多)段合并成一段,用滚动数组记一下,暴力搞就可以了……$O(n*log^2n)$ Orz

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

【NOIP2014模拟8.17】Magical GCD

题目 对于一个由正整数组成的序列, Magical GCD 是指一个区间的长度乘以该区间内所有数字的最大公约数.给你一个序列,求出这个序列最大的 Magical GCD. 分析 根据暴力的思想, \(枚举i,枚举j,a[j]=gcd(a[j],a[i])\) 答案就是\(max(a[j]*(i-j+1))\) 显然,当\(a[j]=a[j-1]\)的时候,\(a[j]\)就一定不会更新ans,所以,弄个双向链表,把\(a[j]\)踢掉. #include <cmath> #include &l