A. Pride (emmmm练习特判的好题)
题目连接 : http://codeforces.com/problemset/problem/891/A
You have an array a with length n, you can perform operations. Each operation is like this: choose two adjacent elements from a, say x and y, and replace one of them with gcd(x, y), where gcd denotes the greatest common divisor.
What is the minimum number of operations you need to make all of the elements equal to 1?
The first line of the input contains one integer n (1 ≤ n ≤ 2000) — the number of elements in the array.
The second line contains n space separated integers a1, a2, ..., an (1 ≤ ai ≤ 109) — the elements of the array.
Print -1, if it is impossible to turn all numbers to 1. Otherwise, print the minimum number of operations needed to make all numbers equal to 1.
5 2 2 3 4 6
5
4 2 4 6 8
-1
3 2 6 9
4
In the first sample you can turn all numbers to 1 using the following 5 moves:
- [2, 2, 3, 4, 6].
- [2, 1, 3, 4, 6]
- [2, 1, 3, 1, 6]
- [2, 1, 1, 1, 6]
- [1, 1, 1, 1, 6]
- [1, 1, 1, 1, 1]
We can prove that in this case it is not possible to make all numbers one using less than 5 moves.
题目大意:
输入一个n,代表有n(1<=n<=2000)个数,输入n个数a1,a2,a3......an(1<=ai<=10^9),接下来你可以进行一种操作,把相邻两个数进行gcd(最大公约数)然后把得到的数附给这两个数中的其中一个
问最少需要多少次操作可以把全部n个数都变成 1 。如果不可以的话输出 ‘ -1 ’。
个人想法 : 一开始思路爆炸,以为操作次数基本为 n , n+1 , n + 2 这三种结果发现wa 3 看了数据发现2000个数操作的3000多次 , 看的我这个难受 , 现在我还不好证明为什么能操作这么多次。
正确思路 : 开始扫一遍看看相邻两个数能不能直接获得gcd为1如果行得通结果为n(前提是n个数全部不为1)不行的话继续,从1~n 挨个算gcd得到的gcd重新附给那两个数,
例如gg=gcd(x[1],x[2]),x[1]=gg,x[2]=gg,(前提是x[1]!=x[2]!=gg)之后次数加1为什么加 1 呢,因为我们只是考虑每种情况实际上我们找的只是其中之一,所以是加一,之后反复,反复直到得到一个1
或者所有的数都相同但不为 1 ,所有数都相同但不为 1 是不可能出现 1 的输出 -1 。 继而还有好多好多特判(考虑问题全面一点)。
AC代码:
#include<stdio.h> #include<stdlib.h> #include<string.h> #include<algorithm> #include<math.h> #include<queue> #include<map> #include<iostream> #include<vector> using namespace std; typedef long long ll; int x[2010]; int gcd(int a,int b){ int maxx=max(a,b); int minn=min(a,b); if(maxx%minn==0){ return minn; } else{ return gcd(maxx%minn,minn); } } int main() { int n; scanf("%d",&n); int yi=0; for(int i=0;i<n;i++){ scanf("%d",&x[i]); if(x[i]==1){ yi++; } } if(n==1&&x[0]==1){ printf("0\n"); return 0; } int ci=0; for(int i=0;i<n-1;i++){ if(gcd(x[i],x[i+1])==1){ printf("%d\n",n-yi); return 0; } } while(1){ for(int i=0;i<n-1;i++){ int gg = gcd(x[i],x[i+1]); if(gg==1){ printf("%d\n",ci+n); return 0; } if(gg!=x[i]||gg!=x[i+1]){ ci++; x[i]=gg; x[i+1]=gg; } } int flag=0; for(int i=1;i<n;i++){ if(x[i]!=x[1]){ flag=1; break; } } if(flag==0){ printf("-1\n"); return 0; } } return 0; }