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 }
方法二: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 }
以上是关于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