比赛的时候读错题+在电脑前时间很少(搞完ab之后就在实验室会宿舍的路上了orz)。。再加上自己构造能力很差。。妥妥的放过了一道c题orz。看来构造(数学yy)能力还得加强
题目:
http://codeforces.com/problemset/problem/798/C
题目大意:
给你一个有序的数,需要你将这个序列构造成一个gcd(a1,a2,a3..an) > 2的序列
有如下操作
[ ai , ai+1 ] -> [ ai+1 - ai , ai+1 + ai ]
该操作每次需要花费1个单位的操作次数我们可以令gcd(x,y) 则有 -> gcd(x - y,x + y) = d
设有gcd(p,q) = 1,则有gcd(pd,qd) = d
有pd = x - y,qd = x + y
则2x = (p + q)d,2y = (q - p)d
该操作可以使公因子*1或者*2
所以,我们可以考虑一下奇偶的问题:
两个都是偶数,不需要操作
两个都是奇数,操作一次变成偶数
一个奇数一个偶数,操作一次变成两个都是奇数,再操作一次变成两个都是偶数先预处理如果所有的gcd已经满足要求,如果不满足再进行操作
我们只需要贪心就好了,第一次将所有两两挨着的奇数都变成偶数
第二次肯定没有挨着的奇数了,就把一奇一偶操作两次变成偶数,答案就出来了orz。(果然我比较菜)
附上代码:
/*
@resources: codeforces798c
@date: 2017-4-25
@author: QuanQqqqq
@algorithm: 构造 greedy
*/
#include <bits/stdc++.h>
#define MAXN 100005
using namespace std;
int gcd(int a,int b){
int c = a % b;
while(c){
a = b;
b = c;
c = a % b;
}
return b;
}
int main(){
int n,tmp,num[MAXN];
scanf("%d",&n);
for(int i = 0;i < n;i++){
scanf("%d",&num[i]);
}
int res = gcd(num[0],num[1]);
for(int i = 2;i < n;i++){
res = gcd(res,num[i]);
}
printf("YES\n");
if(res > 2 || n == 1){
printf("0\n");
return 0;
}
int ans = 0;
for(int i = 0;i < n;i++){
if(num[i] & 1){
if(num[i + 1] & 1 && i + 1 < n){
ans++;
tmp = num[i];
num[i] -= num[i + 1];
num[i + 1] += tmp;
i++;
}
}
}
for(int i = 0;i < n;i++){
if(num[i] & 1 || (i + 1 < n && (num[i + 1] & 1))){
ans += 2;
tmp = num[i];
num[i] -= num[i + 1];
num[i + 1] += tmp;
tmp = num[i];
num[i] -= num[i + 1];
num[i + 1] += tmp;
i++;
}
}
printf("%d\n",ans);
}