C. Mike and gcd problem-递推或者贪心

http://codeforces.com/problemset/problem/798/C
给定你一个数列,你可以进行以下的操作,
a,b –a-b,a+b,让这些数的最大公约数大于1,问你最少的操作是多少
因为d|a && d|b -> d|(ax+by)
d|(a−b) && d|(a+b) -> d|2a && d|2b
所以要将 gcd(ai)=1 转化成 gcd(ai)=2 。
方法1 是用递推。如果最后一个数无法成为偶数,那么就是no,
但是我们会发现,经过操作,总是能把奇数变成偶数的。(自己模拟四种情况就行)
然后根据这四种情况又优化出了贪心的写法。

#include <iostream>
#include <cstdio>
#include <cstdlib>
/*把数论的部分搞定了,递推就不难了。
*/
const int maxn=100009;
const int inf=99999999;
int gcd(int a ,int b)
{ return b==0?a:gcd(b,a%b);
}
int m;
int a[maxn];
int p[maxn];
int solve()
{ for(int i=0;i<m;i++)
   { if(a[i]%2==0)
     p[i]=0;
     else
     p[i]=1;

   }
return 0;
}
int dp[maxn][2];
using namespace std;
int main()
{
   cin>>m;
   for(int i=0;i<m;i++)
    cin>>a[i];
    solve();

    int ans=a[0];
    for(int i=0;i<m;i++)
     ans=gcd(ans,a[i]);
    if(ans==1)
    {   dp[0][!p[0]]=inf;//
        for(int i=1;i<m;i++)
        {  if(p[i]==0)
           { dp[i][0]=min(dp[i-1][1]+2,dp[i-1][0]);
             dp[i][1]=min(inf,inf);
           }
            else
            {  dp[i][0]=min(dp[i-1][0]+2,dp[i-1][1]+1);
               dp[i][1]=min(dp[i-1][0],inf);

            }

        }
        if(dp[m-1][0]!=inf)
            printf("YES\n%d",dp[m-1][0]);
        else
            printf("NO\n");

    }
     else
        printf("YES\n0");
    return 0;
}
#include <iostream>
#include <cstdio>
#include  <cstdlib>
using namespace std;
/*方法是贪心,
先行处理两个奇数的情况,奇数只需要
然后在处理一个奇数一个偶数的情况。
*/
const int maxn=100006;
int a[maxn];
int b[maxn];
int gcd(int a,int b)
{   return b==0?a:gcd(b,a%b);

}
int main()
{   int m;
    cin>>m;
    for(int i=0;i<m;i++)
        {cin>>a[i];
          if(a[i]%2==1)
            b[i]=1;//jishu
          else b[i]=2;
        }
        int sum=a[0];
        for(int i=0;i<m;i++)
             sum=gcd(sum,a[i]);
             if(sum>1)
             {  puts("YES\n0");return 0;

             }
        int ans=0;
    for(int i=0;i<m-1;i++)
    {    if(b[i]==1&&b[i+1]==1)
          {  ans++;
              b[i]=2;
              b[i+1]=2;
          }
    }
     for(int i=0;i<m-1;i++)
     {   if(b[i]==1&&b[i+1]==2||(b[i]==2&&b[i+1]==1))
          {ans+=2;
            b[i]=2;
            b[i+1]=2;
          }
     }
     puts("YES");
    cout<<ans<<endl;
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值