Codeforces Round 1039 (Div. 2)

链接:https://codeforces.com/contest/2128

A. Recycling Center

算法:

    贪心、排序。

思路:

    直接从最小的开始销毁。

关键代码:

void solve()
{
    ll n, c;
    cin >> n >> c;
    vector<ll> a(n);
    for (auto &x : a)
        cin >> x;

    ranges::sort(a, greater<>());

    ll ans = n;
    for (int i = 0; i < n; ++i)
    {
        if (a[i] <= c)
        {
            --ans;
            c /= 2;
        }
    }

    cout << ans << endl;
}

B. Deque Process

算法:

    贪心、构造。

思路:

    一边取一个。

关键代码:

void solve()
{
    int n;
    cin >> n;
    vector<int> p(n + 1);
    for (auto &x : p | views::drop(1))
        cin >> x;

    string ans;
    int l = 1, r = n;
    bool flag = 0;
    while (l < r)
    {
        if (flag)
        {
            if (p[l] >= p[r])
            {
                ans += 'L';
                ++l;
            }
            else
            {
                ans += 'R';
                --r;
            }

            flag = !flag;
        }
        else
        {
            if (p[l] <= p[r])
            {
                ans += 'L';
                ++l;
            }
            else
            {
                ans += 'R';
                --r;
            }

            flag = !flag;
        }
    }

    ans += 'L';
    cout << ans << endl;
}

C. Leftmost Below

算法:

    贪心,数学。

思路:

    可以发现构造第 \(i\) 个元素时,前 \(i – 1\) 个元素必然构造出来了。

    定义 \(minn\) 为前 \(i – 1\) 个元素最小值。

    当前构造 \(a[i]\) 你想让前面的元素都加不到值,只给 \(a[i]\) 加,最多加两次

    第一次加 \(x\) 可选范围为 \([1, minn – 1]\),第二次加 \(x\) 只能选 \(minn\)

    所以每个元素最大为 \(minn * 2 – 1\), 只要大于这个必然构造不出

关键代码:

void solve()
{
    int n;
    cin >> n;
    vector<ll> b(n + 1);
    for (auto &x : b | views::drop(1))
        cin >> x;

    ll minn = INT_MAX;
    for (int i = 1; i <= n; ++i)
    {
        if (b[i] > minn + minn - 1)
        {
            cout << "NO" << endl;
            return;
        }

        minn = min(minn, b[i]);
    }

    cout << "YES" << endl;
}

D. Sum of LDS

算法:

    \(dp\)、组合数学、贪心。

思路:

    定义 \(dp[i]\) 为所有以 \(i\) 结尾的子数组 \(LDS\) 长度之和,那么就答案为:\(∑dp[i]\)

    由 \(max(p_i, p_i + 1) > p_i + 2\) 可知:
        整个数组几乎是完全递减的,可能会有一些位置递增一下,但不会连续递增两次,既 \(p_i < p_i + 1\) 且 \(p_i + 1 < p_i + 2\),这样是不满足题目给出的条件的。

    所以一个子数组的 \(LDS\) = 子数组长度 – 子数组上升的个数。

    每次状态转移考虑把所有以 \(i – 1\) 结尾的子数组延长一个元素到 \(i\)

  • \(p_i – 1 > p_i:\)
    • 前面每个子数组长度都可 \(+1\),以 \(i – 1\) 结尾的子数组有 \(i – 1\) 个,再加上 \([i, i]\),加到一起就是:\(dp[i] = dp[i – 1] + i\)
  • \(p_i – 1 < p_i:\)
    • 由于递增了,需要抛弃 \(p[i]\), 所以前面所有的子数组长度都不变,只会新增 \([i, i]\),所以 \(dp[i] = dp[i – 1] + 1\)

关键代码:

void solve()
{
    int n;
    cin >> n;
    vector<ll> p(n + 1);
    for (auto &x : p | views::drop(1))
        cin >> x;

    ll ans = 1;
    vector<ll> dp(n + 1);
    dp[1] = 1;
    for (int i = 2; i <= n; ++i)
    {
        if (p[i - 1] > p[i])
            dp[i] = dp[i - 1] + i;
        else
            dp[i] = dp[i - 1] + 1;

        ans += dp[i];
    }

    cout << ans << endl;
}

E1. Submedians (Easy Version)

算法:

    前缀和、二分。

思路:

    判断一个元素可不可以当作数组中某个子数组的中位数:

        通常转换成 \(+-1\) 前缀和,既:如果 \(a[i] >= x\) 就令 \(a[i] = 1\), 反之为 \(-1\)。

    此时只需一个子数组的和 \(>= 0\),这个数字就为数组某个子数组的中位数。

    证明:

        当 \(n\) 为偶数时,需要 \(n / 2\) 的元素大于等于 \(x, [latex]n – n / 2\) 的元素小于 \(x\),如果一段区间和大于等于\(0\),既:

\(pre[r] – pre[l – 1] \geq 0 \;\;\Rightarrow\;\; pre[r] \geq pre[l – 1]\)。

        当 \(n\) 为奇数时,需要 \(n / 2 + 1\) 的元素大于等于 \(x\), \(n – n / 2 – 1\) 的元素小于 \(x\),如果一段区间和大于等于\(1\),既:

\(pre[r] – pre[l – 1] >= 1 \Rightarrow pre[r] >= pre[l – 1] + 1\)

但是一个长度为奇数的子数组,其和也必然为奇数,不会出现偶数情况,所以判断 \(>= 0\) 即可。

    由于中位数必然满足单调性,且满足条件最大的可能也会小于等于数组长度,所以只需在 \([1, n]\) 之间二分即可。

    \(check\)函数:

        根据当前中位数,将数组转换成 \(+-1\) 前缀和。

        由于规定区间长度最少为 k, 那么我们就初始令 \(r = k, l = 0\),每次循环让 \(r\) 递增,此时 \(l\) 的取值范围为\([0, r – k]\),每次我们都贪心地选择 \([0, r – k]\) 区间内的最小前缀,这样如果 \(pre[r] >= pre[l]\),就说明 \(x\) 可以当作数组某个子数组的中位数。

关键代码:

void solve()
{
    int n, k;
    cin >> n >> k;
    vector<int> a(n + 1);
    for (int i = 1; i <= n; ++i)
        cin >> a[i];

    ll ansl, ansr;
    auto check = [&](ll val)
    {
        vector<int> pre(n + 1, 0);
        for (int i = 1; i <= n; ++i)
            pre[i] = pre[i - 1] + (a[i] >= val ? 1 : -1);

        for (int i = k, j = 0; i <= n; ++i)
        {
            if (pre[j] > pre[i - k])
                j = i - k;

            if (pre[i] >= pre[j])
            {
                ansl = j + 1;
                ansr = i;
                return 1;
            }
        }

        return 0;
    };

    int l = 1, r = n;
    while (l < r)
    {
        int mid = l + r + 1 >> 1;
        if (check(mid))
            l = mid;
        else
            r = mid - 1;
    }

    check(l);

    cout << l << ' ' << ansl << ' ' << ansr << endl;
}

E2. Submedians (Hard Version)

    还没补。

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇