A.Painting the Ribbon (思维)
题意:
给出nnn种物品,需要用mmm种颜色进行染色,使得:
- 不存在选择kkk个物品,将它们染成同一颜色之后,会使得所有物品颜色一致的方案。
询问能否实现。
分析:
一种颜色的数量不能超过(n−k−1)(n-k-1)(n−k−1),那么最多可以染色m×(n−k−1)m \times (n-k-1)m×(n−k−1)样物品,并且数量需要大于等于nnn。
代码:
#include <bits/stdc++.h>
using namespace std;
int main() {
int T;
cin >> T;
while (T--) {
int n, m, k;
cin >> n >> m >> k;
if ((n - k - 1) * m >= n) {
cout << "YES" << endl;
} else {
cout << "NO" << endl;
}
}
return 0;
}
B.Make It Ugly (思维)
题意:
把一个数组 aaa 称为 "美丽"数组,当且仅当能通过任意次数(可能是零)的以下操作使数组中的所有元素都相同:
- 选择一个索引 iii ( 2≤i≤∣a∣−12 \le i \le |a| - 12≤i≤∣a∣−1 ),例如 ai−1=ai+1a_{i - 1} = a_{i + 1}ai−1=ai+1 ,然后将 aia_iai 替换为 ai−1a_{i - 1}ai−1 。
给出一个漂亮的数组 a1,a2,…,ana_1, a_2, \dots, a_na1,a2,…,an 。要使数组不再美丽,至少要删除多少个元素?禁止交换元素。如果不可能做到,那么输出 −1-1−1。
分析:
如果数组中所有的数字都相同直接输出−1-1−1,因为无法更改开头和结尾。计算和a[0]a[0]a[0]值相同的连续段的最小长度,那么就可以构造出两个与开头结尾不一样的数来构成一个不美丽序列。
代码:
#include <bits/stdc++.h>
using namespace std;
int main() {
int T;
cin >> T;
while (T--) {
int n;
cin >> n;
vector<int> a(n + 1);
for (int i = 0; i < n; i++)
cin >> a[i];
bool flag = 1;
for (int i = 1; i < n; i++)
if (a[i] != a[0])
flag = 0;
if (flag) {
cout << -1 << endl;
continue;
}
int cnt = 0;
int ans = 1e9;
for (int i = 0; i < n; i++) {
if (a[i] == a[0])
cnt++;
else
ans = min(ans, cnt), cnt = 0;
}
if (cnt)
ans = min(ans, cnt);
cout << ans << endl;
}
return 0;
}
C.Long Multiplication (贪心)
题意:
给出两个长度相同的整数 xxx 和 yyy ,由 111 到 999 之间的数字组成。
可以执行以下操作任意多次(可能为零):交换 xxx 中的 iii 个位数和 yyy 中的 iii 个位数。
例如,如果 x=73x=73x=73 和 y=31y=31y=31 中的 222 个位数对调,就可以得到 x=71x=71x=71 和 y=33y=33y=33。
你的任务是可以使用任意次上述操作,最大化 xxx 和 yyy 的乘积。如果有多个答案,请输出任意一个。
分析:
因为x+yx+yx+y为定值,所以xxx和yyy的差值越小,积越大。令最终x≤yx\le yx≤y,那么我们逐位判断,如果前面的位数已经推出x>yx>yx>y,那么尽可能交换后面的位数使得yyy变大。如果之前位数只能推出x=yx=yx=y,那么根据当前位数判断是否能进行交换。
代码:
#include <bits/stdc++.h>
using namespace std;
int main() {
int T;
cin >> T;
while (T--) {
string s1, s2;
cin >> s1 >> s2;
int n = s1.length();
int flag = 0;
for (int i = 0; i < n; i++) {
if (flag == 0) {
if (s1[i] < s2[i])
swap(s1[i], s2[i]);
if (s1[i] > s2[i])
flag = 1;
} else {
if (s1[i] > s2[i]) {
swap(s1[i], s2[i]);
}
}
}
cout << s1 << endl << s2 << endl;
}
return 0;
}
D.Colored Balls (dp)
题意:
有 nnn 种颜色的球,其中 iii 种颜色的球的数量是 aia_iai 。
这些球可以组合成一组。每组最多包含 222 个球,每种颜色的球不超过 111 个。
考虑所有 2n2^n2n 组颜色。对于一组颜色,让我们把它的值表示为这些颜色的球所能分配到的最少组数。例如,如果有三种颜色,分别有 333 、 111 和 777 个球,它们可以组合成 777 组(且不少于 777 ),那么这组颜色的值就是 777 。
你的任务是计算所有 2n2^n2n 种可能的颜色组的值之和。并将答案对998 244 353998\,244\,353998244353 取模。
分析:
将问题转化成:有若干个小球,每个小球具备某种颜色,不同颜色的可以匹配,问最少的分组数。那么我们设最多颜色的小球有mxmxmx个,总数有nnn个,如果mxmxmx超过nnn的一半,那最小分组数就是mxmxmx个,否则就是⌈n2⌉\lceil \frac{n}{2} \rceil⌈2n⌉个。
我们将各种颜色小球的数量排序,然后枚举数量最多的小球有多少个。用背包统计在这之前选择了xxx个小球的方案数,计算答案即可。
代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int mod = 998244353;
int main() {
int T;
T = 1;
while (T--) {
int n;
cin >> n;
vector<LL> a(n);
int m = 0;
for (int i = 0; i < n; i++)
cin >> a[i], m += a[i];
sort(a.begin(), a.end());
vector<LL> dp(m + 1, 0);
dp[0] = 1;
LL ans = 0;
for (auto x: a) {
for (int j = 0; j <= m; j++) {
if (j <= x) {
ans += x * dp[j];
ans %= mod;
} else {
ans += ((x + j + 1) / 2) * dp[j];
ans %= mod;
}
}
for (int j = m; j >= x; j--) {
dp[j] += dp[j - x];
dp[j] %= mod;
}
}
cout << ans << endl;
}
return 0;
}
E. Chain Reaction (数据结构)
题意:
一排站着 nnn 只怪物。第 iii 个怪物的生命值是 aia_iai 。
每隔一秒,你可以选择一只活着的怪物,向它发射一道连锁闪电。闪电会对它造成 kkk 伤害,同时也会向左(向 iii 递减)和向右(向 iii 递增)扩散到只活着的怪物身上,对每只怪物造成 kkk 伤害。当闪电到达死亡怪物或行首/行尾时,就会停止。如果怪物的生命值严格大于 000 ,则视为存活。
例如,考虑以下情况:有三个怪物的健康值分别等于 [5,2,7][5, 2, 7][5,2,7] 和 k=3k = 3k=3 。你可以在 444 秒内将它们全部杀死:
- 向 3th3th3th 的怪物发射连锁闪电,那么它们的生命值为 [2,−1,4][2, -1, 4][2,−1,4] ;
- 向 1th1th1th 怪物发射连锁闪电,则它们的生命值为 [−1,−1,4][-1, -1, 4][−1,−1,4] ;
- 向 3th3th3th 怪物发射连锁闪电,则它们的生命值为 [−1,−1,1][-1, -1, 1][−1,−1,1] ;
- 向 3th3th3th 怪物发射连锁闪电,则它们的生命值为 [−1,−1,−2][-1, -1, -2][−1,−1,−2] 。
从 111 到 max(a1,a2,…,an)\max(a_1, a_2, \dots, a_n)max(a1,a2,…,an) 的每个 kkk ,计算杀死所有怪物所需的最少秒数。
分析:
上述操作等价于每次选择不含000的一段,让段里每个数字都减去111,求出原序列的差分序列,使得操作等价于选择两个数字(x,y)(x,y)(x,y),让dxd_xdx加一,dyd_ydy减一。
通过观察发现。在差分序列中,如果出现一个负数,那么之前一定出现了对应数量的正数,所以我们可以选择一个正数和负数进行配对,就可以删掉一个111 和一个−1-1−1。所以操作数等于差分序列中正数之和。同时可以发现相邻元素的大小关系不会改变,所以我们用整除分块枚举每个位置可能的取值,用差分静态前缀和更新答案。
代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
int main() {
int T;
T = 1;
while (T--) {
int n;
cin >> n;
vector<int> a(n + 2);
int maxval = 0;
for (int i = 1; i <= n; i++) {
cin >> a[i];
maxval = max(maxval, a[i]);
}
const int m = maxval;
vector<LL> d(m + 2);
for (int i = 1; i <= n; i++) {
int x = a[i];
for (int l = 1, r; l < x; l = r + 1) {
int tmp = (x + l - 1) / l;
r = (x + tmp - 2) / (tmp - 1) - 1;
if (a[i] >= a[i - 1]) {
d[l] += tmp;
d[r + 1] -= tmp;
}
if (a[i] <= a[i + 1]) {
d[l] -= tmp;
d[r + 1] += tmp;
}
}
if (a[i] <= a[i + 1]) {
d[x] -= 1;
}
if (a[i] >= a[i - 1]) {
d[x] += 1;
}
}
for (int i = 1; i <= m; i++) {
d[i] += d[i - 1];
cout << d[i] << " ";
}
cout << endl;
}
return 0;
}
赛后交流
在比赛结束后,会在交流群中给出比赛题解,同学们可以在赛后查看题解进行补题。
群号: 704572101,赛后大家可以一起交流做题思路,分享做题技巧,欢迎大家的加入。

2214

被折叠的 条评论
为什么被折叠?



