Educational Codeforces Round 103 题解报告A-D

A. K-divisible Sum

题目大意:

给定 n 个数和一个参数 k ,并构造一个数列 a1an~ 的和能够被给定参数 k 整除,问这样满足条件的数列中的最大值最小是多少

我们考虑一下两种情况:

  1. 给定的 n ≤ k n \le k nk 的时候,我们一定可以通过取平均值并对平均值向上取整得到答案
  2. 给定的 $n > k $ 的时候,这时我们再用 k 直接去分配就不够了,于是我们需要找到第一个大于 n 的 k 的倍数,然后进行上述操作
#include <bits/stdc++.h>
using namespace std;

int main()
{
    int t;
    scanf("%d", &t);
    while (t--)
    {
        int n, m;
        scanf("%d%d", &n, &m);
        if (m < n)
        {
            if (n % m == 0)
                m = n;
            else
                m = (n / m * m) + m;
        }
        
        printf("%.0f\n", ceil((m * 1.0) / n));
    }
    return 0;
}

B. Inflation

题目大意:

给定序列 {p} ,最少需要加多少,使得对于任意
p i + 1 ∑ i = 1 n − 1 p i ≤ k 100 \frac{p_{i+1}}{\sum_{i=1}^{n-1}p_i} \le \frac{k}{100} i=1n1pipi+1100k
分析可知,我们对任意 i ∈ [ 2 , n ] i\in[2,n] i[2,n] , a i + x a_i+x ai+x 可以完全等效于 a 1 + x a_1+x a1+x ,于是我们有一下两种思路:

  1. 遇到不满足上述条件的,我们直接在当前点修改,并将当前加上的值看做是加在 a 1 a_1 a1 上的
  2. 我们直接通过二分,判断$ q_1 $ 加上某个数后是否满足条件,如果满足,缩小范围,否者扩大范围
//直接扫描数组
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int MAX = 1000010;
int n, k;
ll a[MAX], sum;

inline ll check(ll fz)
{
    ll fm = (100 * fz + k - 1) / k;
    return fm;
}

int main()
{
    int t;
    scanf("%d", &t);
    while (t--)
    {
        scanf("%d%d", &n, &k);
        for (int i = 1; i <= n; i++)
            scanf("%lld", &a[i]);

        ll ans = 0;
        sum = a[1];
        for (int i = 2; i <= n; i++)
        {
            if (a[i] * 100 > sum * k)
            {
                ll temp = check(a[i]);
                ans += temp - sum;
                sum = temp;
            }
            sum += a[i];
        }

        printf("%lld\n", ans);
    }
    return 0;
}
//二分法
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int MAX = 10010;
int n, k;
ll a[MAX], b[MAX];

inline bool check(ll mid)
{
    b[1] = a[1] + mid;
    for (int i = 2; i <= n; i++)
    {
        b[i] = b[i - 1] + a[i];
        if (100 * a[i] > k * b[i - 1])
            return false;
    }
    return true;
}

int main()
{
    int t;
    scanf("%d", &t);
    while (t--)
    {
        scanf("%d%d", &n, &k);

        for (int i = 1; i <= n; i++)
            scanf("%lld", &a[i]);

        ll l = 0, r = 1e12;
        while (l < r)
        {
            ll mid = (l + r) / 2;

            if (check(mid))
                r = mid;
            else
                l = mid + 1;
        }

        printf("%lld\n", l);
    }
    return 0;
}

C. Longest Simple Cycle

题目大意:

给出 n 条链,每条链上按顺序分布着 ci 个点,序号从1-ci ,并且给出 2n 个链接,使除1号链外所有的链,都和 i-1 号链相连,具体操作如下

  1. 第一条链被跳过
  2. 第 i 条链第 1 个顶点与第 (i-1) 条链的第 ai 号顶点通过一条边连接
  3. 第 i 链的最后一个顶点与 (i-1) 条链的 bi 号顶点通过一条边连接

问这样构成的一个最大环

思路分析:

我们构造一个一个前缀和数组,这个数组记录的是:

对于第i条链,前 i-1条链在向第 i 条链转移时的最多点个数

那么我们容易得到以下动态规划方程
a n s = m a x ( a n s , s u m [ i ] + c [ i ] ) ans=max(ans,sum[i]+c[i]) ans=max(ans,sum[i]+c[i])
其中 sum[i] 表示前 i-1 条链最多有多少能够向第 i 条链转移,c[i] 即题目中 c[i]

现在我们只需要求出 sum[i] 即可

对于 sum[i] 我们做出如下三种分类:

  1. i=2 时,我们直接计算第一条链即可
  2. a[i]=b[i] 时,这时由于这个点被重复走,所以必定清空前面所有的贡献,新的贡献仅有 1 个点
  3. 非以上两种情况时,sum[i] 的值就是 sum[i-1] 的值加上在 i-1 条链上能走的距离
//开long long
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int MAX = 200010;
ll a[MAX], b[MAX], c[MAX];
ll sum[MAX];
int n;

signed main()
{
    int t;
    scanf("%d", &t);
    while (t--)
    {
        scanf("%d", &n);
        for (int i = 1; i <= n; i++)
            scanf("%lld", &c[i]), sum[i] = 0;
        for (int i = 1; i <= n; i++)
            scanf("%lld", &a[i]);
        for (int i = 1; i <= n; i++)
            scanf("%lld", &b[i]);

        ll ans = 0;
        for (int i = 2; i <= n; i++)
        {
            if (a[i] > b[i])
                swap(a[i], b[i]);

            if (i == 2)
                sum[i] = b[i] - a[i] + 1;
            else if (a[i] == b[i])
                sum[i] = 1;
            else
                sum[i] = max(sum[i - 1] + (c[i - 1] - b[i] + 1) + (a[i]), b[i] - a[i] + 1);

            ans = max(ans, sum[i] + c[i]);
        }
        printf("%lld\n", ans);
    }
    return 0;
}

D. Journey

题目大意:

一条链上分布有 0~n 个点,每一个点中间有一条单向边连接,并用字母 ‘L’ 和 ‘R’表示

若为 L 说明该边方向向左,若为 R 说明该边方向向右

你可以在任意一点开始移动,并且每移动一步,上述边的方向改变一次

要求求出每一个点能够到达的最多点数(若一个点被多次走到,那么仅算一次)

思路分析:

显然,当某一个点左边 RL 交替出现或其右边 LR 交替出现,其能够一直向下走下去

并且,当这种交替状态走到尽头时,一定能够原路返回

那么我们只要求出一个点的左边有多少 L、R交替出现(无顺序)和右边L、R交替出现(无顺序)的最大长度,最终统计答案输出即可

特别的,由于首尾都只能单方向行走,所以需要特判

#include <bits/stdc++.h>
using namespace std;
const int MAX = 300010;
int n, sum1[MAX], sum2[MAX];
char s[MAX];

int main()
{
    int t;
    scanf("%d", &t);
    while (t--)
    {
        scanf("%d%s", &n, s + 1);
        for (int i = 1; i <= n; i++)
            sum1[i] = sum2[i] = 0;

        //预处理
        s[0] = s[1];
        s[n + 1] = s[n];
        for (int i = 1, temp = 1; i <= n; i++)
        {
            if (s[i] != s[i - 1])
                sum1[i] = ++temp;
            else
                sum1[i] = temp = 1;
        }
        for (int i = n, temp = 1; i >= 1; i--)
        {
            if (s[i] != s[i + 1])
                sum2[i] = ++temp;
            else
                sum2[i] = temp = 1;
        }

        //输出
        //第一个特判
        if (s[1] == 'R')
            printf("%d ", sum2[1] + 1);
        else
            printf("1 ");

        for (int i = 1; i < n; i++)
        {
            int sum = 1;
            if (s[i] == 'L')	//当前点能够向左边走
                sum += sum1[i];
            if (s[i + 1] == 'R')	//当前点能够向右边走
                sum += sum2[i + 1];
            printf("%d ", sum);
        }
		//最后一个特判
        if (s[n] == 'L')
            printf("%d\n", sum1[n] + 1);
        else
            printf("1\n");
    }
    return 0;
}
  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
"educational codeforces round 103 (rated for div. 2)"是一个Codeforces平台上的教育性比赛,专为2级选手设计评级。以下是有关该比赛的回答。 "educational codeforces round 103 (rated for div. 2)"是一场Codeforces平台上的教育性比赛。Codeforces是一个为程序员提供竞赛和评级的在线平台。这场比赛是专为2级选手设计的,这意味着它适合那些在算法和数据结构方面已经积累了一定经验的选手参与。 与其他Codeforces比赛一样,这场比赛将由多个问题组成,选手需要根据给定的问题描述和测试用例,编写程序来解决这些问题。比赛的时限通常有两到三个小时,选手需要在规定的时间内提交他们的解答。他们的程序将在Codeforces的在线评测系统上运行,并根据程序的正确性和效率进行评分。 该比赛被称为"educational",意味着比赛的目的是教育性的,而不是针对专业的竞争性。这种教育性比赛为选手提供了一个学习和提高他们编程技能的机会。即使选手没有在比赛中获得很高的排名,他们也可以从其他选手的解决方案中学习,并通过参与讨论获得更多的知识。 参加"educational codeforces round 103 (rated for div. 2)"对于2级选手来说是很有意义的。他们可以通过解决难度适中的问题来测试和巩固他们的算法和编程技巧。另外,这种比赛对于提高解决问题能力,锻炼思维和提高团队合作能力也是非常有帮助的。 总的来说,"educational codeforces round 103 (rated for div. 2)"是一场为2级选手设计的教育性比赛,旨在提高他们的编程技能和算法能力。参与这样的比赛可以为选手提供学习和进步的机会,同时也促进了编程社区的交流与合作。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值