CCPC2018 桂林 G "Greatest Common Divisor"(数学)

UPC备战省赛组队训练赛第十七场

            with zyd,mxl

G: Greatest Common Divisor

题目描述
    There is an array of length n, containing only positive numbers.
    Now you can add all numbers by 1 many times. 
    Please find out the minimum times you need to perform to obtain an array whose greatest common divisor(gcd) is larger than 1 or state that it is impossible.
    You should notice that if you want to add one number by 1, you need to add all numbers by 1 at the same time.


输入
    The first line of input file contains an integer T (1≤T≤20), describing the number of test cases.
    Then there are 2×T lines, with every two lines representing a test case.
    The first line of each case contains a single integer n (1≤n≤1e5) described above.
    The second line of that contains n integers ranging in [1,1e9].


输出
    You should output exactly T lines.
    For each test case, print Case d: (d represents the order of the test case) first. 
    Then output exactly one integer representing the answer. 
    If it is impossible, print -1 instead.
题目描述
样例输入
3

1
2

5
2 5 9 5 7

5
3 5 7 9 11

样例输出
Case 1: 0
Case 2: -1
Case 3: 1
样例输入输出

题意:

  定义a[]数组存储输入的 n 个数;

  求使得 ∀i∈[1,n] GCD(a[i]+x) > 1 的最小的 x;

  如果不存在这样的x,输出-1;

思路:

  将数组 a 排序,去重;

  ①去重后,如果只有一个元素,输出 (a[1] == 1 ? 1:0);

  ②找到相邻两数差值的GCD记为gcd:

    (2.1)如果 gcd == 1 ,输出 -1

    (2.2)反之,所有数肯定可以通过增加 x 使得所有数变为 gcd 的倍数,当然也可以变为gcd因子的倍数,

      求解出最小的x输出;

AC代码:

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define ll long long
 4 const int maxn=1e5+50;
 5 
 6 int n;
 7 int a[maxn];
 8 
 9 int GCD(int _a,int _b)
10 {
11     return _a == 0 ? _b:GCD(_b%_a,_a);
12 }
13 ll Solve()
14 {
15     sort(a+1,a+n+1);
16     int t=unique(a+1,a+n+1)-a;
17     t--;
18     if(t == 1)///情况①
19         return a[1] == 1 ? 1:0;
20 
21     ll gcd=a[2]-a[1];
22     for(int i=2;i <= t;++i)
23         gcd=GCD(gcd,a[i]-a[i-1]);
24 
25     if(gcd == 1)///情况(2.1)
26         return -1;
27     ll ans=(a[1]/gcd+(a[1]%gcd == 0 ? 0:1))*gcd-a[1];///情况(2.2)
28     for(ll i=2;i*i <= gcd;++i)
29     {
30         if(gcd%i != 0)
31             continue;
32         ll j=gcd/i;
33         ///找到最小的 curAns 使得所有数 +curAns 都可以变为 i,j 的倍数
34         ll curAns=(a[1]/i+(a[1]%i == 0 ? 0:1))*i-a[1];
35         curAns=min(curAns,(a[1]/j+(a[1]%j == 0 ? 0:1))*j-a[1]);
36         ans=min(ans,curAns);
37     }
38     return ans;
39 }
40 int main()
41 {
42     int test;
43     scanf("%d",&test);
44     for(int kase=1;kase <= test;++kase)
45     {
46         scanf("%d",&n);
47         for(int i=1;i <= n;++i)
48             scanf("%d",a+i);
49 
50         printf("Case %d: %lld\n",kase,Solve());
51     }
52     return 0;
53 }
View Code

总结:

 1 比赛的时候,只考虑了使所有的数都变成gcd的最小的因子的倍数的情况;
 2 并没有考虑到所有数变成gcd的其他因子的倍数使得答案最小;
 3 赛后,吃完午饭美美的睡上了一觉;
 4 午睡刚醒,就看到队友zyd给我发的G题ac的截图;
 5 一脸懵逼的我问了句为啥????
 6 例如
 7     13 34
 8     差值为21
 9     21的非1的因子有3,7,21
10     所有数都变成3的倍数需要 +2
11     所有数都变成7的倍数需要 +1
12     所有数都变成21的倍数需要 +8
13     答案当然是1啦,所以说,最优解不一定是变成gcd最小因子的倍数
View Code

猜你喜欢

转载自www.cnblogs.com/violet-acmer/p/10802641.html