ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

【题解】Codeforces Round #700 (Div. 2)

2021-07-24 23:32:08  阅读:202  来源: 互联网

标签:int 题解 700 mid long leq 怪物 Div 英雄


前言

蒟蒻的第一把\(Codeforces\),不出意料地成功考砸了。最大的感触就是这次\(CF\)的题目基本都是思维题,很少会出现本蒟蒻刷的水题和模板题。本次比赛的\(A\)题明显是签到题,\(B\)题和\(C\)题涉及的知识点都比较基础,考验的是选手的思维水平。\(D1\),\(D2\)和\(E\),蒟蒻目前的水平还不足以总结。

总体来说,这把打得还算中规中矩,是蒟蒻的真实实力。不像前段时间打的几场水赛,随便打打暴力就混过去了,对实力的提升一点帮助都没有。值得一提的是,\(2\)小时\(15\)分钟的比赛时长真的很可以,本蒟蒻甚至没有扫过一眼后三题的题面。看来,男人不仅要有爆发力和持久,还要追求速度。

\(T1\) \(Yet\) \(Another\) \(String\) \(Game\)

题目链接

题目大意

目前有两个人正在玩游戏。每次可以从给定的由小写字母字符串\(s\)中挑选出一个没有被修改过的位置,将其修改成另外一个和原来不同小写字母。玩家\(A\)的目的是让最终的字符串\(s\)字典序尽量小,玩家\(B\)的目的是让最终的字符串\(s\)字典序尽量大。已知\(A\)是先手,\(B\)是后手,试求字符串\(s\)最终的样子。

输入数据由\(t\)组数据组成,\(t \leq 1000\),字符串的长度\(|s| \leq 50\)。

解题思路

显然,如果要对字典序产生最大的影响,我们一定会选择位置最靠前的位置进行修改。为了让字典序尽量小,\(A\)一定会把这个字母修改成\(a\),如果原来是\(a\)则修改成\(b\);为了让字典序尽量大,\(B\)一定会把这个字母修改成\(z\),如果原来是\(z\)则修改成\(y\)。

\(A\)和\(B\)轮流修改,并且两人一定会选择最靠前的位置。因此,假设第一个位置为\(0\),则偶数位置会被\(A\)修改,奇数位置会被\(B\)修改。按照最优的策略模拟即可。

参考代码

#include <iostream>
#include <string>
using namespace std;

int t;
string s;

int main()
{
    cin >> t;
    while (t--)
    {
        cin >> s;
        for (int i = 0; i < s.length(); i++)
        {
            if (!(i % 2))
            {
                if (s[i] != 'a')
                    s[i] = 'a';
                else
                    s[i] = 'b';
            }
            else
            {
                if (s[i] != 'z')
                    s[i] = 'z';
                else
                    s[i] = 'y';
            }
        }
        cout << s << endl;
    }
    return 0;
}

\(T2\) \(The\) \(Great\) \(Hero\)

题目链接

题目大意

已知有一位英雄和\(n\)只怪物。英雄和怪物都有其对应的生命值和攻击力。英雄的初始生命值为\(B\),攻击力为\(A\)。第\(i\)头怪物的生命值为\(b_{i}\),攻击力为\(a_{i}\)。每一次,英雄都可以选择一只未死亡的怪物并与其战斗,战斗过后英雄和该怪物的生命值分别会变成\(B - a_{i}\)和\(b_{i} - A\)。如果生命值 \(\leq 0\),代表英雄或怪物已经死亡,否则代表存活。试求英雄能否杀死所有的怪物,注意,英雄和最后一头怪物同归于尽也算是杀死所有的怪物。如果能,输出YES,否则输出NO

输入由\(t\)组数据组成,\(t \leq 10^5\),\(A, B \leq 10^6\),\(n \leq 10^5\),\(a_{i}, b_{i} \leq 10^6\)。

解题思路

显然,杀死一头怪物所要消耗的生命值是固定的。设\(cost_{i}\)为英雄杀死第\(i\)头怪物所需要的生命值,显然,\(cost_{i}\)等于杀死第\(i\)头怪物所需要的攻击次数乘上第\(i\)头怪物的攻击力,即\(cost_{i} = \lceil \frac{b_{i}}{A} \rceil \times a_{i}\)。注意,假如英雄攻击怪物后怪物已经死亡,英雄的生命值依然会减少。

设\(sum\)为\(\sum\limits_{i = 1}^n cost_{i}\)。\(c_{i}\)为杀死其他\(n - 1\)头怪物后,杀死最后的第\(i\)头怪物的前一回合英雄所剩的生命值。\(c_{i}\)等于杀死所有怪物所需要的生命值\(sum\),减去怪物发动的最后一次攻击给英雄造成的伤害\(a_{i}\)。如果\(c_{i} > 0\),说明英雄有能力给怪物最后一击,答案为YES,否则,英雄在给怪物最后一击之前就已经去世,答案为NO

枚举最后一头杀死怪物,如果\(max(c_{i}) > 0\),说明英雄可以杀死所有的怪物,反之,英雄在杀死所有怪物前就已经去世。至此,这道题可以在\(O(nt)\)的时间复杂度内解决,无需贪心策略和排序操作。

参考代码

#include <cstdio>
using namespace std;
#define maxn 100005

int t, n;
long long A, B;
long long a[maxn], b[maxn], c[maxn], h[maxn];

long long get_ceil(long long a, long long b)
{
    if (a % b)
        return a / b + 1;
    return a / b;
}

int main()
{
    bool flag;
    long long sum;
    scanf("%d", &t);
    while (t--)
    {
        sum = 0;
        flag = false;
        scanf("%lld%lld%d", &A, &B, &n);
        for (int i = 1; i <= n; i++)
            scanf("%lld", &a[i]);
        for (int i = 1; i <= n; i++)
        {
            scanf("%lld", &b[i]);
            c[i] = get_ceil(b[i], A);
            sum += c[i] * a[i];
        }
        for (int i = 1; i <= n; i++)
        {
            h[i] = B - sum + a[i];
            if (h[i] > 0)
            {
                flag = true;
                break;
            }
        }
        if (flag)
            printf("YES\n");
        else
            printf("NO\n");
    }
    return 0;
}

\(T3\) \(Searching\) \(Local\) \(Minimum\)

题目链接

题目大意

本题是交互式题目

定义一个\(Local\) \(Minimum\)为\(1\)到\(n\)的全排列\(a\)中的某个位置\(i\),且\(i\)满足\(a_{i}\)小于其左右两侧的最小值,即\(a_{i} < min(a_{i - 1}, a_{i + 1})\)。\(a_{n}\)的右侧\(a_{n + 1} = a_{0} = \infty\)。现在,你可以像评测系统提出不超过\(100\)个问题,作为回答,评测系统会给出第\(i\)个位置上的元素\(a_{i}\)。询问结束后,你需要给出任意一个\(Local\) \(Minimum\)。

\(n \leq 10^5\),\(a_{i} \leq n\)。

解题思路

显然,对于这种查询某个元素的题目,我们需要用二分搜索来解决。显然,我们需要分析这个问题是否单调。

假设\(Local\) \(Minimum\)所在的区间为\(\left[ l, r \right]\),其中点为\(mid\)。现在给出重要前提:目前的中点可能不是答案。假如\(a_{mid} < a_{mid + 1}\),说明区间\(\left[ l, mid \right]\)一定是单调递增的,下面给出证明:

因为中点\(mid\)可能不是答案,且\(a_{mid} < a_{mid + 1}\),说明\(a_{mid} > a_{mid - 1}\),否则\(mid\)就是答案。同理,\(a_{mid - 1} > a_{mid - 2}, a_{mid - 2} > a_{mid - 3}\)……由此可知区间\(\left[ l, mid \right]\)一定是单调递增的。

同理,假如\(a_{mid} > a_{mid + 1}\),问题同样单调。由此可以确定,这道题的正解就是二分。假如\(a_{mid} < a_{mid + 1}\),在左区间内继续查找;反之在右区间内继续查找。

参考代码

#include <cstdio>
using namespace std;
#define maxn 100005

int n;
int a[maxn];

int main()
{
    scanf("%d", &n);
    int l = 1, r = n;
    while (l < r)
    {
        int mid = (l + r) / 2;
        if (!a[mid])
        {
            printf("? %d\n", mid);
            fflush(stdout);
            scanf("%d", &a[mid]);
        }
        if (!a[mid + 1])
        {
            printf("? %d\n", mid + 1);
            fflush(stdout);
            scanf("%d", &a[mid + 1]);
        }
        if (a[mid] < a[mid + 1])
            r = mid;
        else
            l = mid + 1;
    }
    printf("! %d\n", l);
    return 0;
}

标签:int,题解,700,mid,long,leq,怪物,Div,英雄
来源: https://www.cnblogs.com/Ling-Lover/p/700-div2.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有