Educational Codeforces Round 152 (Rated for Div. 2)
C:
题意:
给你一个长度为n的01字符串s,以及q个询问每次询问给出一个区间[l, r],你需要将区间内的字符排序,问q次询问之后可以得到多少个不同的01字符串?
思路:
直接暴力模拟时间复杂度为O(q(r - l)log(r - l))会超时,通过暴力做法可以发现时间主要卡在了排序上,那要怎么样才能简化排序呢?
假设区间[l, r]为00010101111,可以直观的发现真正有效的排序区间[l + 3, r - 4],因为头部和尾部已经是有序的了,这启发我们在每次询问的时候都要去找到有效的[l, r]以此来简化排序,那要如何简化呢?
我们可以通过记录每个位置右边的一个1,和左边的第一个0来达到简化效果。
void solve()
{
int n, q; cin >> n >> q;
string s; cin >> s;
std::vector<int> last1(n, n); // 右边第一个1
std::vector<int> last0(n, -1); // 左边第一个0
for(int i = 0;i < n;i++) // 注意边界
{
if(i > 0)
{
last0[i] = last0[i - 1];
}
if(s[i] == '0')
{
last0[i] = i;
}
if(n - i - 1 < n - 1)
{
last1[n - i - 1] = last1[n - i];
}
if(s[n - i - 1] == '1')
{
last1[n - i - 1] = n - i - 1;
}
}
set<PII> ms;
while(q--)
{
int l,r;std::cin >> l >> r;
if(last1[l - 1] > last0[r - 1])
{
ms.emplace(-1, -1);
} else
{
ms.emplace(last1[l - 1], last0[r - 1]);
}
}
cout << ms.size() << endl;
}
D:
题意:
给你一个只有0, 1, 2组成的数组,你可以进行两种操作:1. 选择一个数花一块钱把它变成红色。 2. 选择一个红色的数让它减一,顺便选左右两个数中的一个也变成红色。
问你最少花多少钱可以把数组全变成红色,初始数组全为蓝色
思路:
对于操作二我们知道,如果2是红色的则可以免费把他的两边都变成红色,是1的话可以让一边变成红色,所以直接贪心先把2都变成红色,把2变成红色之后,这个红色可以一直通过操作二传递到碰到0为止
举个例子:001121100,如果我们先把2变成红色那么子区间0112110都会因为操作二变成红的,代价为一枚金币.
void solve()
{
int n; cin >> n;
std::vector<int> a(n + 1);
std::vector<int> st(n + 1);
for (int i = 1; i <= n; i++) cin >> a[i];
int ans = 0;
for (int i = 1; i <= n; i++)
{
if (a[i] == 2 && !st[i])
{
ans ++;
int l = i;
while (a[l] != 0 && l > 0) st[l] = 1, l--;
st[l] = 1;
int r = i;
while (a[r] != 0 && r <= n) st[r] = 1, r++;
st[r] = 1;
}
}
for (int i = 1; i <= n; i++)
{
if (a[i] == 1 && !st[i])
{
ans++;
bool used = false;
if (!st[i - 1] && i > 1) st[i - 1] = 1, used = true;
int r = i;
while (a[r] != 0 && r <= n) st[r] = 1, r++;
if (!used) st[r] = 1;
}
}
for (int i = 1; i <= n; i++) if (!st[i]) ans++;
cout << ans << endl;
}

浙公网安备 33010602011771号