zoukankan      html  css  js  c++  java
  • C

    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;
    }
    
    
  • 相关阅读:
    ASP.NET MVC处理JsonResult返回时间DateTime问题
    ASP.NET MVC显示HTML字符串
    视图加载时自动执行铵钮事件
    呼叫外部js文件并使用其内部方法
    共用字段事件与结果不同关系与处理
    STOP:c0000218 {Registry File Failure}
    RDLC报表打印
    在Gridview如何进行每行单元格比较
    ASP.NET MVC在布局页上使用模型(model)
    Razor练习4
  • 原文地址:https://www.cnblogs.com/tomjobs/p/10617581.html
Copyright © 2011-2022 走看看