专栏文章

MX Day 8

生活·游记参与者 1已保存评论 0

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
0 条
当前快照
1 份
快照标识符
@minoyvba
此快照首次捕获于
2025/12/02 05:59
3 个月前
此快照最后确认于
2025/12/02 05:59
3 个月前
查看原文

T1:

1759649497281.png
做法:
  1. 我们可以发现这道题就是要我们删掉几个数剩下m个数,要我们将其两两相加,求最大的和;
  2. 所以我们可以想到二分答案的做法
  3. 我们二分一个k,将小于等于k/2的数全部找出来,他们是不用删掉的;
  4. 我们再枚举这些数之间的那些大于k/2的那些数
  5. 如果有加起来小于k的结果,我们就保留;
  6. 最后,我们返回留下的数的个数,如果不足m,那么就要增大k,否则减小k

code:

CPP
#include <bits/stdc++.h>
using namespace std;
#define int long long
inline int read()
{
    register int x = 0, f = 1;
    char ch = getchar();
    while (ch < '0' || ch > '9')
    {
        if (ch == '-')
            f = -1;
        ch = getchar();
    }
    while (ch >= '0' && ch <= '9')
    {
        x = x * 10 + ch - '0';
        ch = getchar();
    }
    return x * f;
}
// int n;
// vector<int> cur;
int a[1000009];
int u, n, m;
int check(int mid)
{
    vector<int> cur;
    // cur.clear();
    int cnt = 0;
    for (int i = 1; i <= n; i++)
    {
        if (a[i] * 2 <= mid)
        {
            cur.push_back(i);
        }
    }
    // cout << "siz=" << cur.size() << endl;
    if (cur.empty())
    {
        return false;
    }
    else if (cur.size() == 1)
    {
        // cout << "???\n";
        for (int i = 1; i <= n; i++)
        {
            if (i != cur[0] && a[i] + a[cur[0]] <= mid)
            {
                return 2;
            }
        }
        return 1;
    }
    // else
    // {
    for (int i = 0; i + 1 < cur.size(); i++)
    {
        for (int j = cur[i] + 1; j < cur[i + 1]; j++)
        {
            if (max(a[cur[i]], a[cur[i + 1]]) + a[j] <= mid)
            {
                cnt++;
                break;
            }
        }
    }
    // cout << "cnt=" << cnt << endl;
    for (int i = 1; i < cur[0]; i++)
    {
        if (max(a[cur[0]], a[cur.back()]) + a[i] <= mid)
        {
            // cout << "shuchu=" << cur.size() + cnt + 1 << endl;
            return cur.size() + cnt + 1;
        }
    }
    for (int i = cur.back() + 1; i <= n; i++)
    {
        if (max(a[cur[0]], a[cur.back()]) + a[i] <= mid)
        {
            // cout << "shuchu=" << cur.size() + cnt + 1 << endl;
            return cur.size() + cnt + 1;
        }
    }
    // cout << "shuchu=" << cur.size() + cnt << endl;
    return cur.size() + cnt;
}
signed main()
{
    freopen("necklace.in", "r", stdin);
    freopen("necklace.out", "w", stdout);
    u = read();
    n = read();
    m = read();
    int maxn = 0;
    for (int i = 1; i <= n; i++)
    {
        a[i] = read();
        maxn = max(maxn, a[i]);
    }
    int l = 1, r = maxn * 2 + 1;
    while (l < r)
    {
        int mid = l + r >> 1;
        // cout << "l=" << l << " r=" << r << " mid=" << mid << endl;
        int ans = check(mid);
        // cout << "now=" << ans << endl
        //      << endl;
        if (ans >= m)
        {
            r = mid;
        }
        else
        {
            l = mid + 1;
        }
    }
    cout << l << endl;
    return 0;
}

T2:

1759650720742.png
做法:
  1. 反正这个题的关键点是第一个条件,第二个条件我们可以用DP顺序轻松压过去;
  2. 首先,我们设dp[i][j][k]表示前i个点,有j棵树,其中前i个点缺少K个儿子;
  3. 之后,就是三种讨论(其中l表示钦定这棵树有几个儿子): 1759651437114.png

评论

0 条评论,欢迎与作者交流。

正在加载评论...