Educational Codeforces Round 172 (Rated for Div. 2) 赛事记录

又要熬夜.

A. Greedy Monocarp

题意

你有 \(n\) 个箱子, 每个箱子最初有 \(a_i\) 个硬币.

现在有一个人, 他会贪心地按硬币多少从大到小拿箱子, 最终使得总共拿取的数量至少为 \(k\).

你现在想要他拿最少的硬币, 所以需要向里面添加硬币.

求必须添加的最少数量.

思路

贪心板子题.

我们先让其从大往小拿箱子, 直到剩余所需硬币数量小于箱子内的硬币个数为止.

这个剩余所需硬币数量即为答案.

#include "iostream"
#include "algorithm"

using namespace std;

constexpr int N = 52;

int n, k, a[N];

void init()
{
    cin >> n >> k;
    for (int i = 1; i <= n; ++i)
        cin >> a[i];
    sort(a + 1, a + n + 1);
    return;
}

void calculate()
{
    int tot = k, pos = n;
    while (1)
    {
        if (tot < a[pos] or pos == 0)
            break;
        tot -= a[pos];
        --pos;
    }
    cout << tot << '\n';
    return;
}

void solve()
{
    init();
    calculate();
}

int main()
{
    int T;
    cin >> T;
    while (T--)
        solve();
    return 0;
}

T2

题意

如图.

思路

依旧贪心板子题.

考虑 Alice, 对其来说一定是先选数量少的弹珠更优(因为更有可能集齐).

而对于 Bob, 他想破坏 Alice 的计划, 所以他一定会尽可能地使 Alice 集不齐一种颜色.

而 Alice 是先手, 所以对于数量为一的弹珠, 她一定可以取到.

这样, 容易发现, 最优策略即为排序后隔一个取一个.
模拟即可.

#include "iostream"
#include "algorithm"

using namespace std;

constexpr int N = 1e3 + 10;

int n, a[N], cnt[N];
bool vis[N];

void init()
{
    cin >> n;
    for (int i = 1; i <= n; ++i)
        cnt[i] = vis[i] = 0;
    for (int i = 1; i <= n; ++i)
        cin >> a[i], ++cnt[a[i]];
    sort(a + 1, a + n + 1, [](int x, int y)
         { return cnt[x] == cnt[y] ? x < y : cnt[x] < cnt[y]; });
    return;
}

void calculate()
{
    int ans = 0;
    for (int i = 1; i <= n; i += 2)
    {
        if (cnt[a[i]] == 1 and !vis[a[i]])
            ++ans;
        if (!vis[a[i]])
            ++ans, vis[a[i]] = 1;
    }
    cout << ans << '\n';
    return;
}

void solve()
{
    init();
    calculate();
}

int main()
{
    int T;
    cin >> T;
    while (T--)
        solve();
    return 0;
}

T3

题意

思路

考虑最终贡献:

\[(cnt1_{x_1} - cnt0_{x_1}) \times 0 + ((cnt1_{x_2} - cnt1_{x_1}) - (cnt0_{x_2} - cnt0_{x_1})) \times 1 + ... + ((cnt1_{x_n} - cnt1_{x_{n-1}}) - (cnt0_{x_n} - cnt0_{x_{n-1}})) \times (n - 1) \]

\(cnt_1,\ cnt_0\) 即为前 \(i\) 为 1, 0 的个数.

展开化简得:

\[(cnt0_{x_1}-cnt1_{x_1})+(cnt0{x_2}-cnt1{x_2})+...+(cnt0_{x_{n-1}}-cnt1{x_{n-1}})+(n-1) \times (cnt1_{x_n}-cnt0_{x_n}) \]

最后的 \((cnt1_{x_n}-cnt0_{x_n})\) 为定值, 先不考虑.

可以发现每一对括号内的 \(x_i\) 是互不影响的, 所以我们可以从大到小贪心地取(将 \((cnt0_{x_i}-cnt1_{x_i})\) 看做一个整体).

这样就又变成了贪心板子题.

#include "iostream"
#include "algorithm"
#include "numeric"
#include "cstring"

using namespace std;

constexpr int N = 2e5 + 10;

int n, k;
string s;
int cnt0[N], cnt1[N];
int f[N];

void init()
{
    memset(cnt0, 0, sizeof cnt0);
    memset(cnt1, 0, sizeof cnt1);
    cin >> n >> k;
    cin >> s, s = " " + s;
    for (int i = 1; i <= n; ++i)
    {
        cnt0[i] = cnt0[i - 1] + (s[i] == '0');
        cnt1[i] = cnt1[i - 1] + (s[i] == '1');
    }
    iota(f + 1, f + n + 1, 1);
    sort(f + 1, f + n + 1, [](int x, int y)
    {
        int dx=cnt0[x]-cnt1[x],dy=cnt0[y]-cnt1[y];
        if (dx==dy)
            return x<y;
        return dx>dy; 
    });
    return;
}

void calculate()
{
    int tot = 0, pos = 1;
    while (1)
    {
        if (tot >= k or pos == n + 1)
            break;
        tot += cnt0[f[pos]] - cnt1[f[pos]];
        tot += cnt1[n] - cnt0[n];
        ++pos;
    }
    if (pos == n + 1)
        pos = -1;
    cout << pos << '\n';
    return;
}

void solve()
{
    init();
    calculate();
}

int main()
{
    int T;
    cin >> T;
    while (T--)
        solve();
    return 0;
}

T4

题意

思路

排序 + 二分查找.

#include "iostream"
#include "algorithm"
#include "set"

using namespace std;

constexpr int N = 2e5 + 10;

int n;
struct Node
{
    int l, r;
    int id;
    friend bool operator<(Node x, Node y)
    {
        if (x.l ^ y.l)
            return x.l < y.l;
        return x.r > y.r;
    }
} a[N];
long long ans[N];

void init()
{
    cin >> n;
    for (int i = 1; i <= n; ++i)
    {
        cin >> a[i].l >> a[i].r;
        a[i].id = i, ans[i] = 0;
    }
    return;
}

set<int> s;

void calculate()
{
    sort(a + 1, a + n + 1);
    for (int i = 1; i <= n; ++i)
    {
        auto it = s.lower_bound(a[i].r);
        if (it != s.end())
            ans[a[i].id] += (*it) - a[i].r;
        s.insert(a[i].r);
    }
    s.clear();
    for (int i = 1; i <= n; ++i)
    {
        a[i].l = 1e9 - a[i].l;
        a[i].r = 1e9 - a[i].r;
        swap(a[i].l, a[i].r);
    }
    sort(a + 1, a + n + 1);
    for (int i = 1; i <= n; ++i)
    {
        auto it = s.lower_bound(a[i].r);
        if (it != s.end())
            ans[a[i].id] += (*it) - a[i].r;
        s.insert(a[i].r);
    }
    s.clear();
    for (int i = 1; i ^ n; ++i)
    {
        if (a[i].l == a[i + 1].l and a[i].r == a[i + 1].r)
            ans[a[i].id] = ans[a[i + 1].id] = 0;
    }
    for (int i = 1; i <= n; ++i)
        cout << ans[i] << '\n';
    return;
}

void solve()
{
    init();
    calculate();
    return;
}

int main()
{
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    cout.tie(nullptr);
    int T;
    cin >> T;
    while (T--)
        solve();
    return 0;
}

后补.

posted @ 2024-12-03 00:25  Steven1013  阅读(186)  评论(0)    收藏  举报