首页 > 代码库 > CF798C Mike and gcd problem

CF798C Mike and gcd problem

思路:

首先如果数列的最大公约数大于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 }

 

CF798C Mike and gcd problem