Educational Codeforces Round 172 Solution
A. Greedy Monocarp
题目大意
有N个箱子,第i个箱子里有Ai个硬币,有一个人会从多到少拿这些箱子。
现在你可以给一个箱子加若干硬币,请你使这个人可以拿到刚好K个硬币时停下拿箱子,要求加入的硬币数量尽量少。
解题思路
排个序,然后从大到小加,加到刚好不能再多加一个箱子为止,结果就是K-sum。
void solve()
{
int n, k;
cin >> n >> k;
vi v(n);
fore(i, v) cin >> i;
sort(all(v));
reverse(all(v));
int sum = 0;
rep(i, n) {
sum += v[i];
if (sum >= k) break;
if (i != n - 1)
if (sum < k && sum + v[i + 1] > k) {
cout << k - sum << endl;
return;
}
}
cout << k - sum << endl;
}
B. Game with Colored Marbles
题目大意
两个人玩游戏,桌子上有N个不同颜色的弹珠,他们可以轮流选择弹珠拿走,最后拿完的时候记分,积分规则如下:
- 有一个不同颜色的弹珠加一分
- 完全拿完了一种颜色的弹珠加一分
两个人都采取最佳策略,问Alice最后的分数。
解题思路
对于单个的弹珠两个人肯定是轮流拿,剩下的弹珠Alice都能抢到一个。
int cnt[1005];
void solve()
{
int n;
cin >> n;
vi v(n);
memset(cnt, 0, sizeof(cnt));
fore(i, v) {
cin >> i;
cnt[i]++;
}
int cnt1 = 0, cnt2 = 0;
repo(i, 1000) {
if (cnt[i] == 1) cnt1++;
else if (cnt[i] != 0) cnt2++;
}
int ans = (cnt1 + 1) / 2 * 2 + cnt2;
cout << ans << endl;
}
C. Competitive Fishing
题目大意
有一个序列,0表示Alice,1表示Bob,你可以把整个序列分成m段,对于第一段的积分为0,第二段积分为1,第三段积分为3...,两个人分别根据01在哪个段内加分。
现在Bob想领先Alice至少k分,问最少要分多少段(分段方式自选)
解题思路
考虑在某个位置划一刀带来的贡献,贡献就是后缀所有的位置的积分都会+1,那么Bob领先的差值就会增加后缀1的个数减去后缀0的个数。
那么对于每个位置都计算一下后缀1的个数减去0的个数,然后排个序算最少要划几刀就可以了。
int cnt[1005];
void solve()
{
int n;
cin >> n;
vi v(n);
memset(cnt, 0, sizeof(cnt));
fore(i, v) {
cin >> i;
cnt[i]++;
}
int cnt1 = 0, cnt2 = 0;
repo(i, 1000) {
if (cnt[i] == 1) cnt1++;
else if (cnt[i] != 0) cnt2++;
}
int ans = (cnt1 + 1) / 2 * 2 + cnt2;
cout << ans << endl;
}
D. Recommendations
题目大意
有N个区间,一个区间如果完全包含另一个区间,那么就被称作是这个区间的predictor,求每个区间的所有predictor的相同覆盖段长度。
解题思路
显然相同覆盖段长度是这些predictor的最小的R-最大的L,那么就是一个二维数点,求以LR为XY轴的二维平面内,左上角的区域中最小的R和最大的L。
代码从X轴扫的,其实扫Y轴更方便。
const int m = 1e9 + 2;
int n, s[200005];
struct su {
int x, y, id;
bool operator<(const su& temp)const {
if (x == temp.x) return y > temp.y;
return x < temp.x;
}
}a[200005];
int ans[200005];
void add(int x, int v) {
for (;x <= n;x += x & -x) s[x] = max(s[x], v);
}
int ask(int x) {
int res = 0;
for (;x;x -= x & -x) res = max(s[x], res);
return res;
}
void solve()
{
cin >> n;
set<int> q;
vector<int> f;
unordered_map<int, int> mp;
for (int i = 1;i <= n;++i) {
int x, y;
cin >> x >> y;
a[i].x = x;
a[i].y = y;
a[i].id = i;
f.push_back(a[i].y);
s[i] = 0;
}
sort(all(f));
reverse(all(f));
unique(all(f));
for (int i = 0;i < f.size();++i) {
if (i > 0 && (f[i] > f[i - 1])) break;
mp[f[i]] = i + 1;
}
sort(a + 1, a + n + 1);
repo(i, n) {
if (i > 1) {
q.insert(a[i - 1].y);
add(mp[a[i - 1].y], a[i - 1].x);
}
if ((i > 1 && a[i].x == a[i - 1].x && a[i].y == a[i - 1].y) || (i < n && a[i].x == a[i + 1].x && a[i].y == a[i + 1].y)) {
ans[a[i].id] = 0;
continue;
}
auto xx = q.lower_bound(a[i].y);
if (xx == q.end()) {
ans[a[i].id] = 0;
continue;
}
int y = ask(mp[a[i].y]);
if (y == 0 || (*xx) < y) {
ans[a[i].id] = 0;
continue;
}
ans[a[i].id] = (*xx) - y - (a[i].y - a[i].x);
}
repo(i, n) {
cout << ans[i] << "\n";
}
}