codeforces Educational Round 88
A、Berland Poker
题意:
给出$n$张牌,其中有$m$个鬼,$k$个人,保证$k$整除$n$,这$k$个人都随机拿相同数量的牌。得分是鬼最多的人鬼的数量减去其他人中鬼最多的人鬼的数量。求得分的最大值。
题解:
首先先一个人的牌全是鬼,然后剩下的鬼要最多的最少,显然平均分即可。
AC代码:
1 #include <bits/stdc++.h> 2 using namespace std; 3 void solve() 4 { 5 int n, m, k; 6 scanf("%d%d%d", &n, &m, &k); 7 int tmp = n / k; 8 if (tmp <= m) 9 printf("%d\n", int(tmp - ceil((1.0 * m - tmp) / (1.0 * k - 1)))); 10 else 11 printf("%d\n", m); 12 } 13 int main() 14 { 15 int T; 16 scanf("%d", &T); 17 while (T--) 18 solve(); 19 return 0; 20 }
B、New Theatre Square
题意:
给出一个$n\times m$的矩阵,格子只有白色和黑色,现在需要把白色的格子重新涂一次,涂$1\times 1$格子需要$x$代价,涂$1\times 2$格子需要$y$代价,求最小代价。
题解:
计算一下后者的平均成本和前者的大小,如果小,能满足条件的就尽量用后者,否则一律使用只涂一个格子的方法。
AC代码:
1 #include <bits/stdc++.h> 2 using namespace std; 3 const int N = 1e3 + 5; 4 char mp[N][N]; 5 void solve() 6 { 7 int n, m, x, y; 8 scanf("%d%d%d%d", &n, &m, &x, &y); 9 for (int i = 1; i <= n; ++i) 10 scanf("%s", &mp[i][1]); 11 bool f = 0; 12 if (2 * x > y) 13 f = 1; 14 int ans = 0; 15 for (int i = 1; i <= n; ++i) 16 for (int j = 1; j <= m;) 17 { 18 if (mp[i][j] == '*') 19 { 20 ++j; 21 continue; 22 } 23 if (!f || j == m || mp[i][j] != mp[i][j + 1]) 24 ans += x, ++j; 25 else 26 ans += y, j += 2; 27 } 28 printf("%d\n", ans); 29 } 30 int main() 31 { 32 int T; 33 scanf("%d", &T); 34 while (T--) 35 solve(); 36 return 0; 37 }
C、Mixing Water
题意:
给出温度是$h$的热水,温度是$c$的冷水,热水冷水交替倒进一个无限容量的容器,温度是$t=\frac{a\times h+b\times c}{a + b}$(设$a$是热水的量,$b$是冷水的量),求混合的水最接近给出混合物温度$t$时,最少需要几桶水?
题解:
显然如果混合物的温度小于等于高低温的平均值(小于容易遗漏),则必然是$2$桶,如果混合物的温度是高温水的温度,那么就是$1$。其他情况我们令$b$是冷水的桶数,则$b+1$是热水的桶数那么我们可以计算出混合物的温度是$\frac{(b+1)\times h+b\times c}{2\times b+1}$。求得$b = \frac{h-t}{2\times t-h-c}$,这样子我们就确定了$b$,考虑到这个b不一定能除尽,所以求$b+1$,然后比较。注意如果$b$和$b+1$的对应的混合物的温差距一样,应选择$b$。
AC代码:
1 #include <bits/stdc++.h> 2 using namespace std; 3 void solve() 4 { 5 int h, c, x; 6 scanf("%d%d%d", &h, &c, &x); 7 if ((c + h) >> 1 >= x) 8 { 9 printf("2\n"); 10 return; 11 } 12 if (x == h) 13 { 14 printf("1\n"); 15 return; 16 } 17 int b = (x - h) / (h + c - 2 * x); 18 int ans = b; 19 double ans1 = abs(x - ((1.0 * (1ll * h + c) * b + h) / (2.0 * b + 1ll))); 20 double ans2 = abs(x - ((1.0 * (1ll * h + c) * (b + 1) + h) / (2.0 * b + 3ll))); 21 if (ans1 > ans2) 22 ++ans; 23 printf("%d\n", ans * 2 + 1); 24 } 25 int main() 26 { 27 int T; 28 scanf("%d", &T); 29 while (T--) 30 solve(); 31 return 0; 32 }
D、Yet Another Yet Another Task
题意:
给出一个序列,求出连续子段和减去段中最大值的最大值。序列长度$n\leq 1e5$,$-30\leq a_i\leq 30$。
题解:
这个题其实是不好做的,因为要减去段中最大值的话,就不能按照正常的最大子段和去做。考虑$dp$的话,可以设置状态$dp_{ij}$,表示到达第$i$个数,段中最大值为$j$的最大的和。然后考虑到最大值的范围就是$[0,max(a_i)]$。所以直接枚举最大值,这样子就要忽略大于当前枚举的最大值的值,其他的就按照最大连续子段和处理,求出的最大连续子段减去当前枚举的值就是当前值的答案,再取最大值即可。
AC代码:
1 #include <bits/stdc++.h> 2 using namespace std; 3 const int N = 1e5 + 5; 4 int n, a[N]; 5 int main() 6 { 7 scanf("%d", &n); 8 for (int i = 1; i <= n; ++i) 9 scanf("%d", &a[i]); 10 int ans = 0; 11 for (int i = 0; i < 31; ++i) 12 { 13 int sum = 0; 14 for (int j = 1; j <= n; ++j) 15 { 16 if (a[j] > i) 17 { 18 sum = 0; 19 continue; 20 } 21 sum += a[j]; 22 ans = max(ans, sum - i); 23 if (sum < 0) 24 sum = 0; 25 } 26 } 27 printf("%d\n", ans); 28 return 0; 29 }
E、Modular Stability
题意:
求出一个长度是$k$的序列,并且序列中的数不超过$n$,并且对于每一个非负整数$x$,这个序列的任意排列$a_{p_1},a_{p_2},...,a_{p_k}$,式子$(...((x\ mod\ a_{p_1})mod\ a_{p_2})mod\ ...)$的值相等,求这样的序列的个数。
题解:
要满足这个对于任意一个整数的条件,这个序列一定是有规律的。因为是对任意排列,上述式子的值都不变,我们不妨假定$a_1<a_2<...<a_k$。要对于所有排列的值都相等。所以我们可以思考这个应该是跟最小的一个是相关的。考虑序列只有两个,如果两个不是倍数关系,如$3$和$2$,我们可以找到反例:$4$,所以我们考虑序列其他的数应该和最小的数成倍数关系。这样子我们就可以枚举这个最小的值,然后从它的符合范围的倍数中,选择$k-1$个,所以总和就是$\sum \limits ^{\lfloor \frac{n}{k} \rfloor}_{i=1} C^{k}_{\lfloor \frac{n}{i} \rfloor -1}$.
AC代码:
1 #include <bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 const int N = 5e5 + 5; 5 const ll mod = 998244353; 6 ll c[N]; 7 ll qpow(ll a, ll b, ll p) 8 { 9 ll res = 1; 10 while (b) 11 { 12 if (b & 1) 13 res = res * a % p; 14 a = a * a % p; 15 b >>= 1; 16 } 17 return res; 18 } 19 void init(int k, int n) 20 { 21 c[k] = 1; 22 for (int i = k + 1; i <= n; ++i) 23 { 24 c[i] = c[i - 1] * i % mod; 25 c[i] = c[i] * qpow(i - k, mod - 2, mod) % mod; 26 } 27 } 28 int main() 29 { 30 int n, k; 31 scanf("%d%d", &n, &k); 32 init(k - 1, n); 33 ll ans = 0; 34 for (int i = 1; i <= n / k; ++i) 35 ans = (ans + c[n / i - 1]) % mod; 36 printf("%lld\n", ans); 37 return 0; 38 }