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 }
View Code

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 }
View Code

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 }
View Code

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 }
View Code

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 }
View Code

 

posted @ 2020-06-11 20:01  Aya_Uchida  阅读(134)  评论(0编辑  收藏  举报