您的位置:首页 > 其它

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

2017-05-18 23:06 459 查看
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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: