CodeForces

来源:互联网 发布:nba单场数据记录 编辑:程序博客网 时间:2024/06/03 11:00

题目链接:点击打开链接

题意:

给你一个序列,每次可以选两个相邻的数,取最大公约数,然后将最大公约数替换其中一个数。问最少操作几次可以将所有数都变为1。

思路:

可以发现,当出现了一个1,以后每一次操作都可以把一个数变为1。那么问题就变成了出现第一个1需要多少步?由于我们不知道第一个1会出现在哪里,所以就需要每次求取所有相邻的gcd。正向遍历每次替换前面的数,这样就能保证下一对数还是原来的数。有人可能会问:如果n=gcd(a1,a2),m=gcd(a3,a4),gcd(n,m)==1,取gcd的顺序不一样还对吗?

答案是对的。gcd满足结合律。gcd(gcd(gcd(a,b), c), d)==gcd(gcd(a,b),gcd(c,d));

可以发现最多操作n-1次。如果操作超过了n-1次,就输出-1.

代码:

#include<stdio.h>#include<string.h>#include<algorithm>using namespace std;int n,a[2005];int GCD(int a,int b){    if(b==0) return a;    return GCD(b,a%b);}int main(){    while(~scanf("%d",&n))    {        int flag=0;        for(int i=0;i<n;i++)        {            scanf("%d",&a[i]);            if(a[i]==1 && flag!=-1)            {                flag++;            }            if(a[i]==0)            {                flag=-1;            }        }        if(flag>0)        {            printf("%d\n",n-flag);            continue;        }        if(flag==-1)        {            printf("-1\n");            continue;        }        for(int i=1;i<=n;i++)        {            for(int j=0;j<n-i;j++)            {                a[j]=GCD(a[j],a[j+1]);                if(a[j]==1)                {                    flag=1;                    printf("%d\n",n-1+i);                    break;                }            }            if(flag) break;        }        if(flag==0)            printf("-1\n");    }    return 0;}