思路:
首先如果数列的最大公约数大于1,直接输出即可。
否则,设对原数列中的ai和ai+1进行一次操作,分别变为ai - ai+1和ai + ai+1。设新数列的最大公约数为d,则由于d|(ai - ai+1)并且d|(ai + ai+1)得到d|(2ai)且d|(2ai+1)。则d|gcd(a1, a2, ..., 2ai, 2ai+1, ai+2, ..., an)|2gcd(a1, a2, ..., an) = 2。说明进行一次这样的操作最多可以把最大公约数变为原来的2倍。所以我们的目标就是把数列的最大公约数变成2(即把所有的数都变成偶数)。
奇数 + 奇数 = 偶数,奇数 + 偶数 = 奇数,偶数 + 偶数 = 偶数。把奇偶性不同的相邻的两个数都变成偶数需要2次操作,而把相邻的两个奇数都变成偶数需要1次操作,所以首先优先把相邻的奇数处理掉,再处理奇数和偶数相邻的情况。
实现:
1 #include <iostream> 2 using namespace std; 3 4 int gcd(int a, int b) 5 { 6 return !b ? a : gcd(b, a % b); 7 } 8 9 int n, a[100005]; 10 11 int main() 12 { 13 cin >> n; 14 int g = 0; 15 for (int i = 0; i < n; i++) 16 { 17 cin >> a[i]; 18 if (!i) g = a[i]; 19 else g = gcd(g, a[i]); 20 } 21 if (g > 1) 22 { 23 puts("YES\n0\n"); return 0; 24 } 25 int cnt = 0; 26 for (int i = 0; i < n; i++) 27 { 28 if (!(a[i] & 1)) continue; 29 else if (i + 1 < n) 30 { 31 if (a[i + 1] & 1) cnt++; 32 else cnt += 2; 33 i++; 34 } 35 else cnt += 2; 36 } 37 cout << "YES" << endl << cnt << endl; 38 return 0; 39 }
标程:
1 # include <bits/stdc++.h> 2 using namespace std; 3 # define fi cin 4 # define fo cout 5 int main(void) 6 { 7 int n; 8 fi>>n; 9 int g = 0,v,cnt = 0,ans = 0; 10 while (n --) 11 { 12 int v; 13 fi>>v; 14 g = __gcd(g,v); 15 if (v & 1) ++cnt; 16 else ans += (cnt / 2) + 2 * (cnt & 1),cnt = 0; 17 } 18 ans += (cnt / 2) + 2 * (cnt & 1); 19 fo << "YES\n"; 20 if (g == 1) 21 fo << ans << ‘\n‘; 22 else 23 fo << "0\n"; 24 cerr << "Time elapsed :" << clock() * 1000.0 / CLOCKS_PER_SEC << " ms" << ‘\n‘; 25 return 0; 26 }
原文:http://www.cnblogs.com/wangyiming/p/7158082.html