
Educational Codeforces Round 152 (Rated for Div. 2) 赛后总结
小菜鸡的赛后总结
B.Monsters
- 题意:有n个具有一定生命值的怪物,序号从1到n,每回合可以选择生命值最高的怪物造成k点伤害,如果有多个生命值最高的怪物,选择序号最小的那个,需要从最先死亡的怪物开始到最后死亡的依次输出它们的序号
- 思路:通过模拟可以发现模上k后从大到小排序即可,而对于生命值为k倍数的,其值应为k
bool cmp(PII a, PII b)
{
if (a.first == b.first)
{
return a.second < b.second;
}
return a.first > b.first;
}
void BlueFire()
{
int n, k;
cin >> n >> k;
vector<PII> a(n);
for (int i = 0; i < n; i++)
{
int t;
cin >> t;
t = (t - 1) % k + 1;
a[i] = {t, i + 1};
}
sort(a.begin(), a.end(), cmp);
for (int i = 0; i < n; i++)
cout << a[i].second << " ";
cout << endl;
return;
}
C. Binary String Copying
- 题意:给一个01字符串,要做m次拷贝,其中每次拷贝给出一个l和r,需要对这个字符串中的l到r位置的01序列进行排序,然后计算所有拷贝完成后有多少种不同的字符串
- 思路:我们发现,l和r间有一部分是有序,有一部分是无序的,只需要将l和r都收缩到那一段无序的序列即可,而对这一段排序一定是一样的结果,所以收缩后记录这对l和r到set中自动去重即可,如何收缩,其实就是记录从l右边的第一个1,r左边的第一个0,看它们是否交叉,若交叉,则实际不需要排序,和原数组一样(这里我直接让l和r都变为-1),若不交叉,则需要排序,改变l和r记录即可,需要处理一些边界问题。
void BlueFire()
{
int n, m;
cin >> n >> m;
string s;
cin >> s;
vector<int> left0(n);
vector<int> right1(n);
left0[0] = -1;
right1[n - 1] = -1;
for (int i = 0; i < n; i++)
{
if (i != 0)
left0[i] = left0[i - 1];
if (s[i] == '0')
left0[i] = i;
}
for (int i = n - 1; i >= 0; i--)
{
if (i != n - 1)
right1[i] = right1[i + 1];
if (s[i] == '1')
right1[i] = i;
}
set<PII> res;
while (m--)
{
int l, r;
cin >> l >> r;
if (l == r)
l = r = -1;
else
{
l = right1[l - 1];
r = left0[r - 1];
if (l >= r || l == -1 || r == -1)
l = r = -1;
}
PII t = {l, r};
res.insert(t);
}
cout << res.size() << endl;
return;
}
D. Array Painting
- 题意:给出一个数组,每个数只能是0,1,2,假定最开始每个数都是蓝色的,可以执行两个操作
1.花费一枚硬币,将一个数变成红色
2.选择一个不为0的红色的数,选择一个相邻格的数,将其变为红色,操作完毕后该数的数字-1
- 思路:贪心,可以发现一段非0的数段中,如果有2,花费一枚硬币将其变红,那么这个非0数段包括左右端的0都能直接变红,如果没2(全是1),那么看左端的0是否已经变红了,如果变红了就去变右端的0(从左到右枚举)。总结下来就是先扫描一遍含2非0段,都操作完后扫描全1非0段,最后依次扫描还没有变红的,用硬币即可。
void BlueFire()
{
int n;
cin >> n;
vector<int> a(n + 1);
vector<bool> st(n + 1);
for (int i = 1; i <= n; i++)
cin >> a[i];
int ans = 0;
// 贪心先改2
for (int i = 1; i <= n; i++)
{
if (a[i] == 2 && !st[i])
{
ans++;
st[i] = 1;
int j = i - 1;
// 左
while (j > 0 && a[j])
st[j--] = 1;
if (j > 0)
st[j] = 1;
// 右
j = i + 1;
while (j <= n && a[j])
st[j++] = 1;
if (j <= n)
st[j] = 1;
}
}
// 再改1
for (int i = 1; i <= n; i++)
{
if (a[i] == 1 && !st[i])
{
ans++;
st[i] = 1;
int j = i - 1;
bool flag = 0;
while (j > 0 && a[j])
st[j--] = 1;
if (j > 0 && !st[j])
{
flag = 1;
st[j] = 1;
}
j = i + 1;
while (j <= n && a[j])
st[j++] = 1;
if (j <= n && !st[j] && !flag)
st[j] = 1;
}
}
for (int i = 1; i <= n; i++)
if (!st[i])
ans++;
cout << ans << endl;
return;
}