Greatest Common Divisor 2018CCPC桂林站G题解 备战省赛组队训练赛第十七场

题目描述
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≤105) described above.
The second line of that contains n integers ranging in [1,109].

输出

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

提示

Sample 1: You do not need to do anything because its gcd is already larger than 1.
Sample 2: It is impossible to obtain that array.
Sample 3: You just need to add all number by 1 so that gcd of this array is 2.
题目大意:
T组数据,然后每一组数据有一个整数n,代表着有n个整数,然后题目问在这个序列中需要全部加几个1才能使这些数的gcd大于1,如果不行的话输出-1
分析:
可以这样来考虑:
1.我们先将这n个数据排完序后去重,因为相同的元素是不会影响结果的,但是相同的元素会在后续的处理过程中有影响,下面会说到;
2.去完重之后看着里面还有多少个数,如果是大于1个数,那么继续下面的步骤,否则看第一项是不是1,(这个很重要,因为需要去特判),如果是1,那么答案就直接输出1,其他的情况输出0
3.继续O(n)的操作,求一遍相邻两个数之间的gcd,这样就能求出这n个数的gcd了(为甚求两个相邻的数的gcd呢,想一下,如果求出的gcd是1,也就是说存在互质的情况,什么情况会出现互质呢–相邻或者是它们之间根本就不能构成gcd大于1 的序列,比如 2 5 16 47),如果gcd是1,那么就输出-1,否则就继续进行下面的步骤
4.上面的gcd是不包含第一元素的,因此需要求一下当前的gcd与a[1]的gcd是否是大于1,如果是大于1,那么就gcd=GCD(gcd,a[1]);否则gcd不变,emmmm,剩下的解释我结合代码吧┗( ▔, ▔ )┛

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;
typedef long long ll;
const int N = 1e6+10;
const int INF=0x3f3f3f3f;
const ll LINF=0x3f3f3f3f3f3f3f3f;
const int MOD=1e9+7;
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define Abs(x) ((x)>=0?(x):-(x))
int gcd( int a,int b) {
	return b==0?a:gcd(b,a%b);
}
int a[N],b[N];
int main()
{
    #ifndef ONLINE_JUDGE
    freopen("in.txt","r",stdin);
    #endif // ONLINE_JUDGE
    int T,n;
    scanf("%d",&T);
    for(int id=1;id<=T;id++){
        printf("Case %d: ",id);
      scanf("%d",&n);
      rep(i,1,n) scanf("%d",&a[i]);

      sort(a+1,a+1+n);
      int m=0;
      m=unique(a+1,a+1+n)-(a+1);

      if(m==1){
        if(a[1]==1)
            printf("1\n");
        else
            printf("0\n");
        continue;
      }
      int gc=a[2]-a[1];
      for(int i=3;i<=m;i++)
        gc=gcd(gc,a[i]-a[i-1]);//这个地方不去重会出现问题的,比如2 2 7 7 7

        if(gc>1){
            if(gcd(gc,a[1])>1)
            gc=gcd(gc,a[1]);//为啥有这一步,因为我们需要最小化
            //比如没有上面那一步,gc=16,a[1]=2,那么这个继续下去答案就不对
            for(int i=2;i<=1000000;i++)
            if(gc%i==0){//我们需要找到这个当前最大公约数gc的一个因子,这就能最小化答案
                gc=i;
                break;
            }
            if(a[1]%gc==0)
                printf("0\n");
            else
                printf("%d\n",gc-a[1]%gc);//比如gc=2,a[1]=7,那么就需要+1就能使其变成倍数关系
        }
         else
            printf("-1\n");
    }
    return 0;
 }

自模拟的样例

5
3
1 6 31
4
2 4 4 6
1
1
5
15 25 35 45 55
4
3 3 3 5
Case 1: 4
Case 2: 0
Case 3: 1
Case 4: 0
Case 5: 1

你可能感兴趣的:(思维,数学)