CodeForces

来源:互联网 发布:php编写新闻发布系统 编辑:程序博客网 时间:2024/06/03 21:12

ou 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.

题意:找两个相邻的数x,y,可用GCD(x, y)替代其中的一个(这是一步操作),问你能否将整个序列的元素全部变为1,能的话输出最小操作次数,否则输出-1;
思路:主要是找到第一个1的出现!只要序列有一个1,那么操作次数就是:n - 1,有t个1,那么操作次数就是n - t,根据这个可以特判一下;然后,可以求第i个元素的【i + 1, n】这个区间内最少操作次数对于GCD(a[i], a[j]) = 1,对每一个点都相同处理,结果:最少的操作次数 + n - 1。

#include <cstdio>#include <cmath>#include <algorithm>using namespace std;typedef long long LL;const LL INF = 1e9;const LL MAXN = 2e3 + 100;LL cnt[MAXN];LL GCD(LL a, LL b) {    return !b ? a : GCD(b, a % b);}int main() {    LL n, gcd;    LL res = 0;    scanf("%lld", &n);    for(int i = 1; i <= n; i++) {        scanf("%lld", &cnt[i]);        if(cnt[i] == 1) res++;        if(i == 1) gcd = cnt[i];        else {            gcd = GCD(gcd, cnt[i]);        }    }    if(res) {        printf("%lld\n", n - res);        return 0;    }    if(gcd != 1) {        printf("-1\n");        return 0;    }    LL ans = INF;    for(int i = 1; i <= n; i++) {        LL minn = INF;        gcd = cnt[i];        for(LL j = i + 1; j <= n; j++) {            gcd = GCD(gcd, cnt[j]); //枚举区间,枚举两点不对,gcd时时更新 ;             if(gcd == 1) {                minn = j - i;                 break;            }        }        ans = min(minn, ans);    }    if(ans < INF) printf("%lld\n", ans + n - 1);    else printf("-1\n");    return 0;} /*342 15 35 */ 
原创粉丝点击