2021.8.3题解

本文解析了CodeForces平台上的几道经典算法题目,包括树形DP、构造算法及贪心策略的应用。通过示例代码详细介绍了如何求解最大权值、构造特定序列以及优化烹饪时间等问题。

CodeForces - 1529C

容易发现,每个点的权值只会取 L L L或者 R R R D P [ i ] [ 0 / 1 ] DP[i][0/1] DP[i][0/1]表示根节点 i i i L / R L/R L/R时,子树的最大权值。

代码
#include <bits/stdc++.h>
using namespace std;

const long long N = 1e5 + 5;
long long L[N], R[N];

vector<long long> vec[N];
long long dp[N][2];
void dfs(long long u, long long pre)
{
    for (auto v : vec[u])
    {
        if (v == pre)
            continue;
        dfs(v, u);
        dp[u][0] += max(abs(L[u] - L[v]) + dp[v][0], abs(L[u] - R[v]) + dp[v][1]);
        dp[u][1] += max(abs(R[u] - L[v]) + dp[v][0], abs(R[u] - R[v]) + dp[v][1]);
    }
}
int main()
{
    long long t;
    cin >> t;
    while (t--)
    {
        memset(dp, 0, sizeof dp);
        long long n;
        cin >> n;
        for (int i = 1; i <= n; i++)
            vec[i].clear();
        for (int i = 1; i <= n; i++)
            scanf("%lld %lld", &L[i], &R[i]);
        for (int i = 1; i < n; i++)
        {
            long long u, v;
            scanf("%lld %lld", &u, &v);
            vec[u].emplace_back(v);
            vec[v].emplace_back(u);
        }
        dfs(1, -1);
        cout << '\t' << max(dp[1][0], dp[1][1]) << endl;
    }
    return 0;
}

牛客多校第六场I

无论什么情况都可以构造。

代码
#include <bits/stdc++.h>
using namespace std;

const int N = 1010;
int a[N];
int n, m;

int main()
{
    int t;
    scanf("%d", &t);
    while (t--)
    {
        scanf("%d %d", &n, &m);
        for (int i = 0; i <= n + 1; i++)
            a[i] = 0;
        for (int i = 1; i <= m; i++)
        {
            int l, r;
            scanf("%d %d", &l, &r);
            if (l <= r)
            {
                a[l]++;
                a[r + 1]--;
            }
            else
            {
                a[l]++;
                a[n + 1]--;

                a[1]++;
                a[r + 1]--;
            }
        }
        for (int i = 1; i <= n; i++)
            a[i] += a[i - 1];

        vector<pair<int, int>> vec;
        int l, r, flag = 0;
        a[n + 1] = 0;
        for (int i = 1; i <= n + 1; i++)
        {
            if (a[i])
            {
                if (!flag)
                {
                    flag = 1;
                    l = i;
                }
            }
            else
            {
                if (flag)
                {
                    vec.emplace_back(make_pair(l, i - 1));
                    flag = 0;
                }
            }
        }
        if (vec[0].first == 0 && vec[vec.size() - 1].second == n)
        {
            vec[0].first = vec[vec.size() - 1].first;
            vec.pop_back();
        }

        int len = vec.size();
        cout << len << endl;
        cout << vec[0].first << ' ' << vec[len - 1].second << endl;
        for (int i = 1; i < len; i++)
            cout << vec[i].first << ' ' << vec[i - 1].second << endl;
        cout << endl;
    }
    return 0;
}

牛客多校第六场F

每个牛排至少要独立花费 T i T_i Ti的时间,使用一次交换机会可以让所有锅都尽可能利用上。

因此,最小花费时间为 m a x ( M A X T i , A D V T i ) max(MAX_{T_i},ADV_{T_i}) max(MAXTi,ADVTi)

有了最小花费时间,即可贪心构造。

代码
#include <bits/stdc++.h>
using namespace std;

const long long N = 1e5 + 5;
long long a[N];
int   main()
{
    long long n, m;
    cin >> n >> m;
    long long T = 0, mx = 0;
    for (int i = 1; i <= n; i++)
    {
        cin >> a[i];
        mx = max(mx, 1ll * a[i]);
        T += a[i];
    }
    T = max(mx, T / m + (T % m ? 1 : 0));
    long long id = 1, l = 0;
    for (int i = 1; i <= n; i++)
    {
        if (a[i] + l <= T)
            cout << 1 << ' ' << id << ' ' << l << ' ' << (l += a[i], l) << endl;
        else
        {
            vector<pair<long long , pair<long long , long long >>> vec;
            vec.emplace_back(make_pair(l, make_pair(T, id)));
            vec.emplace_back(make_pair(0, make_pair(a[i] - (T - l), id + 1)));
            ++id, l = a[i] - (T - l);
            sort(vec.begin(), vec.end());
            cout << 2 << ' ' << vec[0].second.second << ' ' << vec[0].first << ' ' << vec[0].second.first;
            cout << ' ' << vec[1].second.second << ' ' << vec[1].first << ' ' << vec[1].second.first << endl;
        }
        if (l == T)
            ++id, l = 0;
    }
    return 0;
}

CodeForces - 1549D

对于 n n n个数存在数 m m m,使得 n n n个数模 m m m的值相同,可以转化为,对 n n n个数做差分,差分后的数取模 m m m 0 0 0

这样,只要差分后的区间 g c d gcd gcd不为1,就存在一个 m m m

区间 g c d gcd gcd可以用 r m q rmq rmq维护。

注意n=1等特殊情况。

下面的代码是没用rmq瞎搞的,感觉挺对,小数据(n<=100)暴力就能AC

代码
#include <bits/stdc++.h>
using namespace std;

const long long N = 2e5 + 10;

long long a[N];
long long b[N];
bool vis[N];

int main()
{
    long long t;
    cin >> t;
    while (t--)
    {
        long long n;
        scanf("%lld", &n);
        for (int i = 0; i <= n + 1; i++)
            vis[i] = 0;
        for (int i = 1; i <= n; i++)
            scanf("%lld", &a[i]);
        if (n == 1)
        {
            cout << 1 << endl;
            continue;
        }
        for (int i = 2; i <= n; i++)
        {
            b[i] = abs(a[i] - a[i - 1]);
        }
        long long ans = 0;
        for (int i = 2; i <= n; i++)
        {
            long long pos = i;
            if ((n >= 100 && vis[pos]) || b[pos] == 1)
            {
                ans = max(ans, 1ll);
                continue;
            }
            long long sum = 2;
            long long g = b[pos];
            for (int i = pos + 1; i <= n; i++)
            {
                long long tmpg = __gcd(g, 1ll * b[i]);
                if (tmpg == 1)
                    break;
                g = tmpg;
                vis[i] = 1;
                sum++;
            }
            for (int i = pos - 1; i >= 2; i--)
            {
                g = __gcd(g, 1ll * b[i]);
                if (g == 1)
                    break;
                vis[i] = 1;
                sum++;
            }
            ans = max(ans, sum);
        }
        cout << ans << endl;
    }
    return 0;
}
源码来自:https://pan.quark.cn/s/fdd21a41d74f 正方教务管理系统成绩推送 简介 使用本项目前: 早晨睡醒看一遍教务系统、上厕所看一遍教务系统、刷牙看一遍教务系统、洗脸看一遍教务系统、吃早餐看一遍教务系统、吃午饭看一遍教务系统、睡午觉前看一遍教务系统、午觉醒来看一遍教务系统、出门前看一遍教务系统、吃晚饭看一遍教务系统、洗澡看一遍教务系统、睡觉之前看一遍教务系统 使用本项目后: 成绩更新后自动发通知到微信 以节省您宝贵的时间 测试环境 正方教务管理系统 版本 V8.0、V9.0 如果你的教务系统页面与下图所示的页面完全一致或几乎一致,则代表你可以使用本项目。 目前支持的功能 主要功能 每隔 30 分钟自动检测一次成绩是否有更新,若有更新,将通过微信推送及时通知用户。 相较于教务系统增加了哪些功能? 显示成绩提交时间,即成绩何时被录入教务系统。 显示成绩提交人姓名,即成绩由谁录入进教务系统。 成绩信息按时间降序排序,确保最新的成绩始终在最上方,提升用户查阅效率。 计算 计算百分制 对于没有分数仅有级别的成绩,例如”及格、良好、优秀“,可以强制显示数字分数。 显示未公布成绩的课程,即已选课但尚未出成绩的课程。 使用方法 Fork 本仓库 → 开启 工作流读写权限 → → → → → 添加 Secrets → → → → → → Name = Name,Secret = 例子 程序会自动填充 尾部的 ,因此你无需重复添加 对于部分教务系统,可能需要在 中添加 路径,如: 开启 Actions → → → 运行 程序 → → 若你的程序正常运行且未报错,那么在此之后,程序将会每隔 30 分钟自动检测一次成绩是否有更新 若你看不懂上述使用...
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

hesorchen

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值