CodeForces - 892C Pride (n个数,求相邻两个数的最大公约数替换其中一个数,看要操作几次使得n个数全部变成1)

探讨了一个数学问题,即通过选取序列中两个相邻元素并用它们的最大公约数替换其中一个元素的操作,来确定使序列中所有元素变为1所需的最少操作次数。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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.

Example
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,看有多少个1,若有num个1,那么直接输出n-num就行了;(2)就是

给出的序列中没有1,那么,看最先找到两个数的最大公约数,用了几次;要如何去找

在这解释一下,我在代码中的我用的方法:问题一:为么外层循环为n-1,问题二:为什么内层循环为n-i,问题三:为什么找相邻的两个数的最大公约数要赋予前一个 问题四:还当做操作一次;

问题一:为什么外层循环为n-1,要是n的数的最大公约数都不为1,那么这个序列就不会为1了,求n的数的最大公约数最多需要n-1次;

问题二:为什么内层循环为n-i;举个例子,求4个数的最大公约数,操作一次后(求任意相邻的两个数的最大公约数代替其中一个数),只需让这两个数的最大公约数,和其他数求最大公约数,这时候就剩3个数求最大公约数了

问题三:首先明确找的是相邻两个数的最大公约数,若相邻两个数的最大公约数等于1了就结束了,若不等于1,替换其中一个,在和相邻数求gcd,对于一个数来说,它被替换成 和左边的数的gcd,或和右边数的gcd都一样,举个例子:2,6,9  任何相邻两个数的gcd都不为1,看6这个数的位置,它可以被替换成和2的gcd,再和9求gcd,或被替换成和9的gcd,再和2求gcd,你看看这两种情况的结果是一样吧;

问题四:为什么找相邻的两个数的最大公约数要赋予前一个 ,还当做操作一次; 为什么要当做一次 首先要明确

gcd(gcd(2,6),9) == gcd(gcd(2.6),gcd(6,9)); 为什么 内层循环要循环遍历;把每一个数都和相邻的求一下gcd,看看那个数和相邻的数 更快找到1;

代码:

#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
#define Max 2010
int n;
int a[Max];

int gcd(int c,int b)&
{
	if(b==0)
		return c;
	return gcd(b,c%b);
}
int main()
{
	int i,j;
	while(~scanf("%d",&n))
	{
		int num = 0;
		for(i=0;i<n;i++)
		{
			scanf("%d",&a[i]);
			if(a[i]==1) num ++;
		}
		if(num!=0)
		{
			printf("%d\n",n-num);
			continue;
		}
		int flag = 0;
		for(i=1;i<=n-1;i++)
		{
			for(j=0;j<n-i;j++)
			{
				a[j] = gcd(a[j],a[j+1]);
				if(a[j]==1)
				{
					printf("%d\n",i+n-1);
					flag = 1;
					break;
				} 
			}
			if(flag)
				break;
		}
		if(!flag)
			printf("-1\n");
	}
	return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值