Atcoder Beginner Contest 364 A-E

A - Glutton Takahashi

思路:

  • 跳过

以下是代码部分,代码参考来源——jiangly

#include <bits/stdc++.h>

using namespace std;

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    int n;
    cin >> n;
    vector<string> s(n);
    for(int i = 0; i < n; i ++)
        cin >> s[i];

    for(int i = 1; i < n - 1; i ++)
        if(s[i] == "sweet" && s[i - 1] == s[i])
        {
            cout << "No\n";
            return 0;
        }
    cout << "Yes\n";

    return 0;
}

B - Grid Walk

思路:

  • 模拟

以下是代码部分,代码来源——jiangly

#include <bits/stdc++.h>

using namespace std;

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    int h, w;
    cin >> h >> w;

    int x, y;
    cin >> x >> y;
    x --, y --;

    vector<string> c(h);

    for(int i = 0; i < h; i ++)
        cin >> c[i];

    string s;
    cin >> s;

    for(char op : s)
    {
        int nx = x;
        int ny = y;
        if(op == 'L')
            ny --;
        else if(op == 'R')
            ny ++;
        else if(op == 'U')
            nx --;
        else
            nx ++;
        if(nx >= 0 && nx < h && ny >= 0 && ny < w && c[nx][ny] == '.')
            x = nx, y = ny;
    }
    cout << x + 1 << " " << y + 1 << '\n';

    return 0;
}

C - Minimum Glutton

思路:

  • 跳过

以下是代码部分, 代码参考来源——jiangly

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

using i64 = long long;

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    int n;
    i64 x, y;
    cin >> n >> x >> y;

    vector<int> a(n), b(n);

    for(int i = 0; i < n; i ++)
        cin >> a[i];

    for(int i = 0; i < n; i ++)
        cin >> b[i];

    int ans = n;
    sort(a.begin(), a.end(), greater<>());
    sort(b.begin(), b.end(), greater<>());

    for(int i = 0; i < n; i ++)
    {
        x -= a[i];
        if(x < 0)
            ans = min(ans, i + 1);
    }

    for(int i = 0; i < n; i ++)
    {
        y -= b[i];
        if(y < 0)
            ans = min(ans, i + 1);
    }
    cout << ans << '\n';

    return 0;
}

D - K-th Nearest

思路.1:

  • 二分范围d,并二分判断[ b − d , b + d b - d, b + d bd,b+d]内有几个 a i a_i ai
  • 当范围内 a i a_i ai的数量等于 K K K时,则输出范围 d d d

思路步骤:
1.二分所求d的范围
2.对于 [ x − d , x + d ] [x - d, x + d] [xd,x+d]的范围内,查找有几个 a i a_i ai
3.查找区间内 a i a_i ai的数量可以用二分查找。
4.经过两次二分查找得出d。

以下是代码部分,代码参考来源——jiangly

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

using i64 = long long;

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    int n, q;
    cin >> n >> q;
    vector<int> a(n), b(q), k(q);

    for(int i = 0; i < n; i ++)
        cin >> a[i];

    for(int i = 0; i < q; i ++)
        cin >> b[i] >> k[i];

    sort(a.begin(), a.end());

    for(int i = 0; i < q; i ++)
    {
        int l_d = 0, r_d = 2e8;

        while(l_d < r_d)
        {
            int x = (l_d + r_d) / 2;
            int l = b[i] - x;
            int r = b[i] + x;

            int cnt = upper_bound(a.begin(), a.end(), r) - lower_bound(a.begin(), a.end(), l);

            if(cnt >= k[i])
                r_d = x;
            else l_d = x + 1;
        }
        cout << l_d << '\n';
    }

    return 0;
}

思路.2

  • 利用 l s t lst lst维护长度为 k k k的区间
  • l s t lst lst代表距离 b i b_i bi从小到大的 k i k_i ki个数的剩余部分, l s t − 1 lst - 1 lst1代表插入一个 a i a_i ai后还要插入的 a i a_i ai的数量。
  • 每次往做或者往右插入 l s t / 2 lst / 2 lst/2

思路步骤:

  1. 首先从小到大排列 a a a数组。
  2. 二分查找 a a a数组中距离 b b b最近的位置p。
  3. l s t = k − 1 lst = k-1 lst=k1,每次向左或者向右扩展以p为起点的区间。
  4. 直到区间长度为 k k k,停止扩展。
  5. 比较区间左边界和右边界,输出较大的那个。

以下是代码部分,代码参考来源——YoSakuraAkina

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

int a[100009];

int main()
{
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    cout.tie(nullptr);
    int n, q;
    cin >> n >> q;
    for (int i = 0; i < n; i++)
        cin >> a[i];

    //从小到大排序,使其有序
    sort(a, a + n);
    while (q--)
    {
        int b, k;
        cin >> b >> k;
        //查询离b最近的a的位置
        int p = lower_bound(a, a + n, b) - a;
        p = min(p, n - 1);
        //更加精确离b最近的a的位置
        if (p > 0 && abs(a[p - 1] - b) < abs(a[p] - b)) p--;
        //如果k=1,直接得出结果
        if (k == 1)
        {
            cout << abs(a[p] - b) << '\n';
            continue;
        }
        //一开始,左边右边的边界均为p
        //需要插入的a_i为lst = k - 1
        int l = p, r = p, lst = k - 1;
        while (lst > 1)
        {
            //利于边界判断
            int m1 = l - lst / 2;
            int m2 = r + lst / 2;
            //如果p在最左边
            if (l == 0)
            {
                r += lst;
                lst = 0;
                break;
            }
            //如果p在最右边
            if (r == n - 1)
            {
                l -= lst;
                lst = 0;
                break;
            }
            //如果左边界越界
            if (m1 < 0)
            {
                m1 = 0;
                //判断应该延长左边界还是右边界
                //延长后,更新左边界和右边界
                //并更新lst
                if (abs(a[m1] - b) < abs(a[m2] - b))
                {
                    lst -= l - m1;
                    l = m1;
                }
                else
                {
                    r = m2;
                    lst -= lst / 2;
                }
            }
            //如果右边界越界
            else if (m2 > n - 1)
            {
                m2 = n - 1;
                //判断应该延长左边界还是右边界
                if (abs(a[m1] - b) < abs(a[m2] - b))
                {
                    l = m1;
                    lst -= lst / 2;
                }
                else
                {
                    lst -= m2 - r;
                    r = m2;
                }
            }
            //如果均范围合法
            else
            {
                if (abs(a[m1] - b) < abs(a[m2] - b))
                    l = m1;
                else
                    r = m2;
                lst -= lst / 2;
            }
        }
        //如果还需插入一个数字
        if (lst == 1)
        {
            if (l > 0 && abs(a[l - 1] - b) < abs(a[r + 1] - b) || r == n - 1)
                l--;
            else
                r++;
        }
        //取大的输出
        if (abs(a[l] - b) > abs(a[r] - b))
            cout << abs(a[l] - b) << '\n';
        else
            cout << abs(a[r] - b) << '\n';
    }

    return 0;
}

E - Maximum Glutton

思路:

  • dp动态规划
  • 定义 d p [ i ] [ j ] = { v } dp[i][j] = \{v\} dp[i][j]={v}
  • d p dp dp[道菜的数量][甜度] = {此时最少的咸度}。

这样设定状态,减少时间复杂度。类似于01背包的做法

以下是代码部分,代码参考来源——jiangly

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

int main()
{
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    cout.tie(nullptr);

    int N, X, Y;
    cin >> N >> X >> Y;
    //定义dp数组
    //dp[吃的菜的数量][甜度] = {最少的咸度}
    //初始化设置咸度为无穷大
    vector dp(N + 1, vector<int>(X + 1, Y + 1));
    //甜度为0时,咸度必定为0
    dp[0][0] = 0;

    for(int i = 0; i < N; i ++)
    {
        int A, B;
        cin >> A >> B;
		//前i餐,甜度为x到A的状态转移
        for(int c = i; c >= 0; c --)
            for(int d = X; d >= A; d --)
                dp[c + 1][d] = min(dp[c + 1][d], dp[c][d - A] + B);
    }

    int ans = 0;
  	//找寻甜度和咸度均达标的时候的最大的i的值
    for(int i = 0; i < N; i ++)
        for(int x = 0; x < X; x ++)
            if(dp[i][x] <= Y)
            //注意下标的统一
                ans = max(ans, i + 1);
    cout << ans << '\n';

    return 0;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值