Codeforces round #1550 Educational Codeforces Round 111 [Rated for Div. 2] (A~C)题解

本文介绍了三个算法问题的解决方案:1)寻找满足特定条件的最短好数组;2)根据01字符串和成本系数计算最大得分;3)确定不形成曼哈顿距离坏三元组的连续子数组个数。涉及数组操作、字符串处理和距离计算的策略和代码实现。
摘要由CSDN通过智能技术生成

题目链接

A - Find The Array

题意:如果一个数组中任一 a i a_{i} ai满足以下条件之一则称为好数组
1. a i a_{i} ai=1
2. a i a_{i} ai-1或 a i a_{i} ai-2至少一个存在于数组中
给出数组的和 s s s,问最小长度的好数组长度为多少
思路:观察后,由等差数列求和公式发现一个长度为 n n n的好数组元素之和的范围是[ n ( 1 + n ) 2 \frac{n(1+n)}{2} 2n(1+n) , n 2 n^{2} n2](公差分别为1和2).所以只需要找到大于等于 s s s的第一个 n n n
Code:

//不够优雅.jpg
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define gcd __gcd
const int mod = 1e7 + 9;
const int inf = 0x3f3f3f3f;
int main()
{
    int t;
    cin >> t;
    while (t--)
    {
        int s;
        cin >> s;
        int ans;
        for (int i = 1; i <= 100; i++)
        {
            if (i * i >= s)
            {
                ans = i;
                break;
            }
        }
        cout << ans << endl;
    }

    return 0;
}

B - Maximum Cost Deletion

题意:给出一个长度为 n n n的01字符串 s s s与常量 a a a, b b b。你需要删除若干次连续子字符串使字符串为空,每删除一次长度为 l l l的字符串你将获得 a ∗ l + b a*l+b al+b个点数,求能获得的最大点数
思路:因为最终要删除的长度必然是n,所以最终点数与a没有关系,只需要判断b的正负来进行操作。
如果b为正数,那么我们要最大化操作次数使点数最大,即每次删除一个字符
如果b为负数,那么我们要最小化操作次数使点数最大,可以先选择连续次数小的删除,之后剩下的就只有0或1,只需要进行一次删除操作。
Code:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define gcd __gcd
const int mod = 1e7 + 9;
const int inf = 0x3f3f3f3f;
int main()
{
    int t;
    cin >> t;
    while (t--)
    {
        int l, a, b;
        string s;
        cin >> l >> a >> b;
        cin >> s;
        int ans = 0;
        ans += a * l;
        if (b < 0)
        {
            int c1 = 0, c2 = 0;
            for (int i = 0; i < l; i++)
            {
                if (s[i] == '1')
                {
                    int p = i;
                    while (s[p] == '1')
                    {
                        p++;
                    }
                    i = p - 1;
                    c1++;
                }
            }
            for (int i = 0; i < l; i++)
            {
                if (s[i] == '0')
                {
                    int p = i;
                    while (s[p] == '0')
                    {
                        p++;
                    }
                    i = p - 1;
                    c2++;
                }
            }
            // cout << "c1:" << c1 << endl;
            // cout << "c2:" << c2 << endl;
            ans += min(c1, c2) * b + b;
        }
        else
        {
            ans += b * l;
        }
        cout << ans << endl;
    }

    return 0;
}

C - Manhattan Subarrays

题意:假设你有两个点 p = ( x p , y p ) p=(xp,yp) p=(xp,yp) q = ( x q , y q ) q=(xq,yq) q=(xq,yq). 两点的曼哈顿距离为 d ( p , q ) = ∣ x p − x q ∣ + ∣ y p − y q ∣ d(p,q)=|xp−xq|+|yp−yq| d(p,q)=xpxq+ypyq.如果存在三个点使 d ( p , r ) = d ( p , q ) + d ( q , r ) d(p,r)=d(p,q)+d(q,r) d(p,r)=d(p,q)+d(q,r)
这个三元组是坏三元组。现在有一个数组 b 1 , b 2 , … , b m b_{1},b_{2},…,b_{m} b1,b2,,bm,如果任选三个元素组成一个三元组 ( b i , i ) , ( b j , j ) , ( b k , k ) (b_{i},i),(b_{j},j),(b_{k},k) (bi,i),(bj,j),(bk,k)都不是坏三元组,那么这是一个好数组。求 b b b数组的连续子数组为好数组的个数。
思路:不妨设i<j<k,那么由题意可推出这个式子
∣ a i − a k ∣ ≠ ∣ a i − a j ∣ + ∣ a j − a k ∣ \left | a_{i}-a_{k} \right | \ne \left |a_{i}-a_{j}\right |+\left |a_{j}-a_{k}\right | aiak=aiaj+ajak
我们再次假设所选的三个数为递增或递减,发现公式不成立,所以我们选择的连续子数组任选三个数都不能是递增或递减,因此,所选连续子数组最大长度不超过4.
Code:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define gcd __gcd
const int mod = 1e7 + 9;
const int inf = 0x3f3f3f3f;
int a[200005];
long long d(int x1, int y1, int x2, int y2)
{
    return abs(x1 - x2) + abs(y1 - y2);
}
int main()
{
    int t;
    cin >> t;
    while (t--)
    {
        int n;
        cin >> n;
        for (int i = 1; i <= n; i++)
        {
            cin >> a[i];
        }
        if (n == 2)
        {
            cout << 3 << endl;
            continue;
        }
        else if (n == 1)
        {
            cout << 1 << endl;
            continue;
        }
        ll ans = 0;
        ans += 2 * n - 1;
        for (int i = n; i >= 3; i--)
        {
            if (abs(a[i - 2] - a[i]) != abs(a[i - 2] - a[i - 1]) + abs(a[i] - a[i - 1]))
            {
                ans++;
            }
        }
        if (n > 3)
        {
            for (int i = n; i >= 4; i--)
            {
                if (abs(a[i - 2] - a[i]) != abs(a[i - 2] - a[i - 1]) + abs(a[i] - a[i - 1]))
                    if (abs(a[i - 3] - a[i - 1]) != abs(a[i - 3] - a[i - 2]) + abs(a[i - 2] - a[i - 1]))
                    {
                        if (abs(a[i - 3] - a[i]) != abs(a[i - 3] - a[i - 2]) + abs(a[i - 2] - a[i]))
                        {
                            if (abs(a[i - 3] - a[i]) != abs(a[i - 3] - a[i - 1]) + abs(a[i] - a[i - 1]))
                            {
                                ans++;
                            }
                        }
                    }
            }
        }
        cout << ans << endl;
    }
    return 0;
}

为什么没有D、E、F?(因为不会 理直气壮.jpg)doge

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值