codeforces Educational Round 89
A、Shovels and Swords
题意:
两个木棍一个钻石做一把钻石铲,一个木棍两个钻石做一把钻石剑,现在有$a$个木棍,$b$各位钻石,求最多能做多少钻石工具?
题解:
如果两个恰好用完,直接列方程组求解得$\frac {a+b}{3}$,如果有一种东西剩下来了,那么答案就是另一个的数量,所以最终的答案是$min(\frac {a+b}{3}, a, b)$。
AC代码:
1 #include <bits/stdc++.h> 2 using namespace std; 3 const int N = 1e5 + 5; 4 typedef long long ll; 5 typedef pair<int, int> pii; 6 void solve() 7 { 8 int a, b; 9 scanf("%d%d", &a, &b); 10 printf("%d\n", min((a + b) / 3, min(a, b))); 11 } 12 int main() 13 { 14 int T; 15 scanf("%d", &T); 16 while (T--) 17 solve(); 18 return 0; 19 }
B、Shuffle
题意:
给出一个数组长度是$n$,其中$a_x$是$1$,其他都是$0$,给出$m$个操作,每个操作给出我范围$l$,$r$,你可以任意选择两个范围内的位置,可以是一样的位置,然后交换其值,求这$m$个操作结束后,有多少个位置的值是可以变成$1$的。
题解:
首先之前的操作结束后,只要$1$可能到达的位置范围和这次询问的范围有交集,那么显然这次操作的整个范围$1$都是可达的,所以如果之前$1$可以到达的范围和这次操作的范围有交集,则可达范围变成这两个范围的并集,如果没有交集则直接丢弃。
AC代码:
1 #include <bits/stdc++.h> 2 using namespace std; 3 const int N = 1e5 + 5; 4 typedef long long ll; 5 typedef pair<int, int> pii; 6 void solve() 7 { 8 int n, x, m; 9 scanf("%d%d%d", &n, &x, &m); 10 int ql, qr, l, r; 11 ql = qr = x; 12 for (int i = 1; i <= m; ++i) 13 { 14 scanf("%d%d", &l, &r); 15 if (ql > r || qr < l) 16 continue; 17 ql = min(ql, l); 18 qr = max(qr, r); 19 } 20 printf("%d\n", qr - ql + 1); 21 } 22 int main() 23 { 24 int T; 25 scanf("%d", &T); 26 while (T--) 27 solve(); 28 return 0; 29 }
C、Palindromic Paths
题意:
给出一个$01$矩阵,一个人从$(1,1)$出发到达$(n,m)$,只能向右或者向下。他走过地方(包括起点终点)会形成一个$01$串,求最少改变多少个位置,使得这个人走过的所有路径形成的串都是回文串。
题解:
我们画出矩阵中走到某一步可能的位置发现:$i+j=const$,所以为了保证回文,所以正数第$k$步和倒数第$k$步的所有字符都必须一样。这样子我们就可以开个桶,统计$1$的数量,然后就可以顺便推出$0$的数量,取小的值加到答案中。然后注意到,如果路径长度是奇数,那么最中间的一步的字符是任意的,如果是偶数,那么最中间的两步的字符也一定要一样。
AC代码:
1 #include <bits/stdc++.h> 2 using namespace std; 3 const int N = 1e5 + 5; 4 typedef long long ll; 5 typedef pair<int, int> pii; 6 int buc[105]; 7 void solve() 8 { 9 memset(buc, 0, sizeof(buc)); 10 int n, m, a; 11 scanf("%d%d", &n, &m); 12 for (int i = 1; i <= n; ++i) 13 for (int j = 1; j <= m; ++j) 14 { 15 scanf("%d", &a); 16 buc[i + j] += a; 17 } 18 int ans = 0; 19 for (int i = 2; i <= (n + m) / 2; ++i) 20 { 21 int one = buc[i] + buc[n + m - i + 2]; 22 int size; 23 if (i <= min(n, m)) 24 size = (i - 1) * 2; 25 else 26 size = min(n, m) * 2; 27 ans += min(one, size - one); 28 } 29 if ((n + m) % 2 == 1) 30 { 31 int size = min(n, m) * 2; 32 int one = buc[(n + m) / 2 + 1] + buc[(n + m) / 2 + 2]; 33 ans += min(one, size - one); 34 } 35 printf("%d\n", ans); 36 } 37 int main() 38 { 39 int T; 40 scanf("%d", &T); 41 while (T--) 42 solve(); 43 return 0; 44 }
D、Two Divisors
题意:
给出$n$个数,对每个数$a_i$,求出一个$pair(d_1,d_2)$,满足$d_1>1$且$d_2>1$且$gcd(d_1+d_2,a_i)=1$,或者输出$(-1,-1)$表示没有。
题解:
解法一:
考虑$gcd$的性质:$gcd(d_1,d_2) = 1$,则$gcd(d_1 \times d_2, d_1+d_2) = gcd(d_1,d_1+d_2)\times gcd(d_2,d_1+d_2) = 1$,所以我们暴力地找即可。显然,这个$a_i$是素数的时候或者只有一个质因数,一定找不到。
AC代码(加上了记忆化):
1 #include <bits/stdc++.h> 2 #include <unordered_map> 3 using namespace std; 4 const int N = 5e5 + 5; 5 typedef long long ll; 6 typedef pair<int, int> pii; 7 const int M = 1e7 + 5; 8 bool isp[M]; 9 int p[M], tot; 10 void init() 11 { 12 memset(isp, 0x3f, sizeof(isp)); 13 for (int i = 2; i < M; ++i) 14 { 15 if (isp[i]) 16 p[++tot] = i; 17 for (int j = 1; j <= tot && p[j] * i < M; ++j) 18 { 19 isp[p[j] * i] = 0; 20 if (i % p[j] == 0) 21 break; 22 } 23 } 24 } 25 int a[N]; 26 pii ans[N]; 27 int fac[N], top; 28 int n = 1000; 29 int gcd(int a, int b) 30 { 31 return !b ? a : gcd(b, a % b); 32 } 33 pii get_fac(int x) 34 { 35 for (int i = 2; i * i <= x; ++i) 36 if (x % i == 0 && gcd(i, x / i) == 1) 37 return {i, x / i}; 38 return {-1, -1}; 39 } 40 unordered_map<int, pii> mp; 41 void solve() 42 { 43 scanf("%d", &n); 44 for (int i = 1; i <= n; ++i) 45 scanf("%d", &a[i]); 46 for (int i = 1; i <= n; ++i) 47 { 48 if (isp[a[i]]) 49 ans[i] = {-1, -1}; 50 else 51 { 52 if (mp.find(a[i]) == mp.end()) 53 { 54 get_fac(a[i]); 55 if (top == 1) 56 ans[i] = {-1, -1}; 57 else 58 ans[i] = get_fac(a[i]); 59 mp[a[i]] = ans[i]; 60 } 61 else 62 ans[i] = mp[a[i]]; 63 } 64 } 65 for (int i = 1; i <= n; ++i) 66 printf("%d%c", ans[i].first, " \n"[i == n]); 67 for (int i = 1; i <= n; ++i) 68 printf("%d%c", ans[i].second, " \n"[i == n]); 69 } 70 int main() 71 { 72 init(); 73 int T = 1; 74 //scanf("%d", &T); 75 while (T--) 76 solve(); 77 return 0; 78 }
解法二:
上面的$gcd$性质有点难想,我们可以换个想法,设$p_1$是$a_i$最小的质因数,设$a_i=x\times p_1^k$,我们令$d_1=p_1^k,d2=x$,如果其中一个是$1$就是找不到,素数也找不到。正确性显然。
注:代码中的欧拉筛是完整功能的欧拉筛,$pm[i]$是$i$的最小质因子,$pk[i]$是这个最小质因子的幂次$k$,满足$i\%pm[i]^k==0$且$i\%pm[i]^{k+1}!=0$。
AC代码(加上了记忆化):
1 #include <bits/stdc++.h> 2 using namespace std; 3 typedef pair<int, int> pii; 4 const int M = 1e7 + 5; 5 const int N = 5e5 + 5; 6 bool isp[M]; 7 int p[M], pm[M], ps[M]; 8 int tot; 9 void get_p() 10 { 11 memset(isp, 0xff, sizeof(isp)); 12 for (int i = 2; i < M; ++i) 13 { 14 if (isp[i]) 15 p[++tot] = pm[i] = ps[i] = i; 16 for (int j = 1; j <= tot; ++j) 17 { 18 int tmp = i * p[j]; 19 if (tmp >= M) 20 break; 21 isp[tmp] = 0; 22 pm[tmp] = p[j]; 23 if (i % p[j]) 24 ps[tmp] = p[j]; 25 else 26 { 27 ps[tmp] = ps[i] * p[j]; 28 break; 29 } 30 } 31 } 32 } 33 int a[N]; 34 pii ans[N]; 35 void solve() 36 { 37 get_p(); 38 int n; 39 scanf("%d", &n); 40 for (int i = 1; i <= n; ++i) 41 scanf("%d", &a[i]); 42 for (int i = 1; i <= n; ++i) 43 { 44 if (isp[a[i]] || a[i] == ps[a[i]]) 45 ans[i] = { -1,-1 }; 46 else 47 { 48 int tmp = a[i]; 49 ans[i].first = pm[tmp]; 50 tmp /= ps[tmp]; 51 ans[i].second = 1; 52 while (tmp != 1) 53 { 54 ans[i].second *= pm[tmp]; 55 tmp /= ps[tmp]; 56 } 57 } 58 } 59 for (int i = 1; i <= n; ++i) 60 printf("%d%c", ans[i].first, " \n"[i == n]); 61 for (int i = 1; i <= n; ++i) 62 printf("%d%c", ans[i].second, " \n"[i == n]); 63 } 64 int main() 65 { 66 int T = 1; 67 //scanf("%d", &T); 68 while (T--) 69 solve(); 70 return 0; 71 }
E、Two Arrays
题意:
题解:
AC代码: