codeforces 798C.Mike and gcd problem 解题报告

Posted windysai

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了codeforces 798C.Mike and gcd problem 解题报告相关的知识,希望对你有一定的参考价值。

题目意思:给出一个n个数序列:a1,a2,...,an (n的范围[2,100000],ax的范围[1,1e9]

然后想构造一个beautiful的序列 b1,b2, ..., bn,使得最大公约数 gcd(b1,b2,...,bn) > 1。任意ai,ai+1 可以用 ai-ai+1, ai+ai+1 来替换。

问序列 a 构造成 b 的最小操作次数

 

  首先,这个题目是肯定有解的,也就是恒输出yes

     试想一下,相邻两个数之间无非就是四种情况:

     (1)对于同偶情况,不需要做转换,公约数直接为2;

     (2)对于同奇情况,只需要变换一次,两奇数进行加减操作,最终结果是偶数,公约数此时为2

  (3)一奇一偶,变换两次: ai, ai+1 ——》 ai-ai+1, ai+ai+1  ——》2(ai+1,ai) ——》 公约数为2

  此时问题就变成: 构造一个所有序列的公约数为2的最少操作次数。

      当然,在处理序列之前,先判断整个序列是不是已经有公约数了(注意,并不一定为2)

 

两种方法

方法一 :常规贪心+数论

技术分享
 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstdlib>
 4 #include <cstring>
 5 using namespace std;
 6 
 7 const int maxn = 1e5 + 5;
 8 int a[maxn];
 9 
10 int GCD(int b1, int b2)
11 {
12     if (b2 == 0)
13         return b1;
14     return GCD(b2, b1%b2);
15 }
16 
17 int main()
18 {
19     #ifndef ONLINE_JUDGE
20         freopen("in.txt", "r", stdin);
21     #endif // ONLINE_JUDGE
22 
23     int n;
24     while (scanf("%d", &n) !=EOF) {
25        scanf("%d", &a[0]);
26        int t=a[0], cnt = 0;
27        for (int i = 1; i < n; i++) {
28         scanf("%d", &a[i]);
29         t = GCD(t, a[i]);
30         if (t > 1) { cnt++; }
31        }
32        printf("YES\n");
33        if ( cnt == n-1 ) { printf("0\n"); }  // all is even
34        else {
35             // scan two times;
36             int ans = 0;
37             for (int i = 0; i < n; i++) {
38                 if (a[i]%2 && a[i+1]%2 && i+1 < n) {  // two odd
39                     ans += 1;
40                     a[i] = 2;
41                     a[i+1] = 2;
42                 }
43             }
44 
45             for (int i = 0; i < n; i++) {
46                 if (i+1 < n && (a[i]%2 && a[i+1]%2 == 0)|| (a[i]%2 == 0 && a[i+1]%2) ) {   // one odd one even
47                     ans += 2;
48                     a[i+1] = 2;
49                 }
50             }
51             printf("%d\n", ans);
52        }
53     }
54     return 0;
55 }
View Code

 

方法二:dp

技术分享
 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstdlib>
 4 #include <cstring>
 5 using namespace std;
 6 
 7 const int inf = 10000000;
 8 const int maxn = 1e5 + 5;
 9 int a[maxn];
10 // dp[i][0]: 前i-1个数为偶数,第i个数为偶数的最少操作次数
11 // dp[i][1]:  前i-1个数为偶数,第i个数为奇数的最少操作次数
12 int dp[maxn][2];
13 
14 int GCD(int b1, int b2)
15 {
16     if (b2 == 0)
17         return b1;
18     return GCD(b2, b1%b2);
19 }
20 
21 int main()
22 {
23     #ifndef ONLINE_JUDGE
24         freopen("in.txt", "r", stdin);
25     #endif // ONLINE_JUDGE
26 
27     int n;
28     while (scanf("%d", &n) !=EOF) {
29        scanf("%d", &a[0]);
30        int t=a[0], cnt = 0;
31 
32        for (int i = 1; i < n; i++) {
33             scanf("%d", &a[i]);
34             t = GCD(t, a[i]);
35             if (t > 1) { cnt++; }
36        }
37        printf("YES\n");
38        if ( cnt == n-1 ) { printf("0\n"); }  // all 有公约数
39 
40        else {
41             memset(dp, 0, sizeof(dp));
42             dp[0][!(a[0]%2)] = inf;
43 
44             for (int i = 1; i < n; i++) {
45                 if (a[i]%2) {     // odd
46                     dp[i][0] = min(dp[i-1][0]+2, dp[i-1][1]+1);
47                     dp[i][1] = min(dp[i-1][0], inf);
48                 }
49                 else {
50                     dp[i][0] = min(dp[i-1][0], dp[i-1][1]+2);
51                     dp[i][1] = inf;
52 
53                 }
54             }
55             printf("%d\n", dp[n-1][0]);
56        }
57     }
58     return 0;
59 }
View Code

 

以上是关于codeforces 798C.Mike and gcd problem 解题报告的主要内容,如果未能解决你的问题,请参考以下文章

codeforces 798C.Mike and gcd problem 解题报告

Codeforces 798D:Mike and distribution

Codeforces 798D Mike and distribution - 贪心

codeforces 798C Mike and gcd problem

Mike and palindrome CodeForces - 798A

codeforces 798c Mike And Gcd Problem