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?
Input
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.
Output
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.
Examples
Input
5
2 2 3 4 6
Output
5
Input
4
2 4 6 8
Output
-1
Input
3
2 6 9
Output
4
Note
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.
题意:每次可以让相邻两个数字中的一个变成两者的最大公约数。问最少变几次全部变成1
思路:1最先想到的肯定是1和任何数的gcd都等于1,那么我们只要能构造出一个1,就可以得到答案。2自然的想到互质数之间的gcd也等于1,可以线找互质数。3但万一是多个非1非互质之间多次gcd得到1呢?得到次数最优的问题要么DP记录答案选最优,要么直接暴力构造比较得到最优。下面给出的代码就是暴力构造得到最优解的情况。
“思路”中给出了三种情况,分别讨论三种情况即可。
#include <bits/stdc++.h>
#define INF 0x3f3f3f3f
using namespace std;
const int maxn = 2000 + 5;
int num[maxn];
int gcd(int n,int m)
{
if(n < m)
swap(n,m);
return m == 0?n:gcd(m,n % m);
}
int main()
{
int n;
scanf("%d",&n);
int cnt = 0;
int minn = INF;
for(int i = 1;i <= n;i++)
{
scanf("%d",&num[i]);
if(num[i] == 1)
cnt++;
}
int tmp = num[1];
for(int i = 2;i <= n;i++)
{
tmp = gcd(tmp,num[i]);
}
if(cnt >= 1)//一开始就有1,那么就直接按照这些1的位置开始gcd
{
printf("%d
",n - cnt);
return 0;
}
else if (tmp != 1)//全部gcd一遍都不能得到1个1,说明不可能使全部数变成1
{
printf("-1
");
}
else//寻找能构造出1的最小长度
{
for(int i = 1;i <= n;i++)
{
tmp = num[i];
for(int j = i - 1;j >= 1;j--)
{
tmp = gcd(tmp,num[j]);
if(tmp == 1)//得到1个1,计算这个过程的最小长度
{
minn = min(minn,i - j);
break;
}
}
tmp = num[i];
for(int j = i + 1;j <= n;j++)
{
tmp = gcd(tmp,num[j]);
if(tmp == 1)
{
minn = min(minn,j - i);
break;
}
}
}
printf("%d
",minn + n - 1);
}
return 0;
}