首页 > 其他分享 >CF Round 822 Div2 题解

CF Round 822 Div2 题解

时间:2022-09-24 14:12:54浏览次数:78  
标签:farPos int 题解 LL maxv CF 史莱姆 leq 822

比赛链接

A题 Select Three Sticks(签到)

给定 \(n\) 根木棒,第 \(i\) 根木棒的长度为 \(a_i\)。现在我们可以进行操作,每次操作选定一根木棒,将其长度增高或减少 1。问至少需要进行多少次操作,才能使得我们能够选出 3 根木棒,并拼成一个等边三角形?

\(T\leq 100,n\leq 300,1\leq a_i\leq 10^9\)

显然我们只会对这三根木棒进行操作,所以我们只需要枚举这三根木棒,就能 \(O(1)\) 的检查需要多少次操作(看最终长度变成啥就行,比赛后发现变成中间长度那个是最优的)。

直接 \(O(n^3)\) 枚举肯定不行(虽然我觉得 A 题应该把这个放过去),所以我们考虑优化:显然,排序后只需要取相邻三个即可(不相邻的肯定比相邻的劣),这样就把复杂度变成 \(O(n\log n)\) 了。

#include<bits/stdc++.h>
using namespace std;
const int N = 200010;
int n, a[N];
int solve() {
    cin >> n;
    for (int i = 1; i <= n; ++i) cin >> a[i];
    sort(a + 1, a + n + 1);
    int res = 2e9;
    for (int i = 3; i <= n; ++i) {
        int x = a[i - 2], y = a[i];
        res = min(res, y - x);
    }
    return res;
}
int main() {
    int T;
    cin >> T;
    while (T--) cout << solve() << endl;
    return 0;
}

B题 Bright, Nice, Brilliant(构造)

建议直接看原题。

(看了题解后)发现,第 \(i\) 层的亮度至多为 \(i\)(就算把前 \(i-1\) 层的灯都点上,\((i,1)\) 收到的亮度也就是 \(i-1\),加上自己的灯就是 \(i\))。

观察样例,发现一种构造方案:只点亮最两边的房间,投影法发现这样可以符合要求。

#include<bits/stdc++.h>
using namespace std;
void solve() {
    int n;
    cin >> n;
    for (int i = 1; i <= n; ++i)
        if (i == 1) puts("1");
        else {
            printf("1");
            for (int j = 2; j < i; ++j) printf(" 0");
            puts(" 1");
        }
}
int main() {
    int T;
    cin >> T;
    while (T--) solve();
    return 0;
}

C题 Removing Smallest Multiples(贪心,数学)

给定集合 \(S=\{1,2,3,\cdots,n\}\),现在我们可以进行多次操作,每次操作选定一个正整数 \(k\),然后删除 \(S\) 里面的最小的 \(k\) 的倍数(包括 \(k\) 自己)。问至少需要删多少次,才能使得 \(S\) 变成集合 \(T\) ?(\(T\) 是给定的一个 \(S\) 的子集)

\(T\leq 10^4,1\leq n,\sum n\leq 10^6\)

要删掉某个数,应该选一个尽可能小的因数,并且这个因数的相对较小的倍数(比这个数小的)都要删。

那么我们直接贪心(或者说有点类似素数筛),从小到大枚举 \(x\),看 \(x\) 能删掉哪些数(碰到一个不能删的就 break 掉,否则判断这个数是不是之前被删掉,没被删掉的话就用 \(x\) 来删就行了),复杂度大概最多 \(O(n\log n)\)。

#include<bits/stdc++.h>
using namespace std;
using LL = long long;
const int N = 1000010;
int n, a[N];
char s[N];
LL solve() {
    scanf("%d%s", &n, s + 1);
    memset(a, 0, sizeof(int) * (n + 1));
    LL ans = 0;
    for (int i = 1; i <= n; ++i)
        if (s[i] == '0') {
            for (int j = i; j <= n; j += i)
                if (s[j] == '0') {
                    if (a[j] == 0) ans += i, a[j] = 1;
                }
                else break;
        }
    return ans;
}
int main() {
    int T;
    cin >> T;
    while (T--) cout << solve() << endl;
    return 0;
}

D题 Slime Escape(贪心)

给定一个数轴,位置下标从 1 到 n,第 \(i\) 个位置有一个血量为 \(a_i\) 的史莱姆。现在我们要控制位置在 \(k\) 处的史莱姆,通过左右跳动的方式到达位置 \(0\) 或者 \(n+1\)。

我们的史莱姆可以左右跳动(每次一格),当目标位置有一个史莱姆的时候就吃掉它,然后自身的血量就加上它的血量。但是注意,有的史莱姆的血量是负数,这意味着吃掉它后我们的血量会变少。当血量变成负数时,我们的史莱姆就 G 了,我们不希望这种情况发生。

问:我们能否到达目标位置?

\(T\leq 2*10^4,3\leq n,\sum n\leq 2*10^5,-10^9\leq a_i\leq 10^9,a_k\geq 0\)

有这样一种思路:我们首先判断能不能向右到达终点,达不到的话就向右取一个最大子段和,吃完后看看能不能向左到达终点,达不到的话就再向左取一个最大字段和,然后再向右,持续下去,直到到达终点。至于无解,就这样判断:发现当前状态下,无论是向左还是向右都无法到达终点,且最大子段和也不再存在(不可能通过吃一段史莱姆的方式来增加血量了),这时输出无解即可。

这样反复走的时间似乎有点高,但实际上它是 \(O(n)\) 的:因为我们记录一下已经吃掉的史莱姆的范围,每次只从这个范围的左右端点扩展,类似两个指针往外拓,每个史莱姆至多吃一次,所以总复杂度是 \(O(n)\) 的。

思路其实还好,主要是写起来烦,还要记录状态啥的。

#include<bits/stdc++.h>
using namespace std;
using LL = long long;
const int N = 200010;
int n, k; LL a[N];
struct Node { int farPos, vpos; LL x; };
Node getR(LL x, int p) {
    LL s, maxv; int farPos, vpos;
    s = x, farPos = n;
    for (int i = p + 1; i <= n; ++i)
        if ((s += a[i]) < 0) { farPos = i - 1; break; }
    maxv = x, vpos = p, s = x;
    for (int i = p + 1; i <= farPos; ++i)
        if ((s += a[i]) > maxv) maxv = s, vpos = i;
    return (Node){farPos, vpos, maxv};
}
Node getL(LL x, int p) {
    LL s, maxv; int farPos, vpos;
    s = x, farPos = 1;
    for (int i = p - 1; i >= 1; --i)
        if ((s += a[i]) < 0) { farPos = i + 1; break; }
    maxv = x, vpos = p, s = x;
    for (int i = p - 1; i >= farPos; --i)
        if ((s += a[i]) > maxv) maxv = s, vpos = i;
    return (Node){farPos, vpos, maxv};
}
//
bool solve() {
    scanf("%d%d", &n, &k);
    for (int i = 1; i <= n; ++i) scanf("%lld", &a[i]);
    int l = k, r = k; LL x = a[k];
    while (true) {
        Node R = getR(x, r); x = R.x;
        if (R.farPos == n) return true;
        Node L = getL(x, l); x = L.x;
        if (L.farPos == 1) return true;
        if (l == L.vpos && r == R.vpos) return false;
        l = L.vpos, r = R.vpos;
    }
    return true;
}
int main() {
    int T;
    scanf("%d", &T);
    while (T--) puts(solve() ? "YES" : "NO");
    return 0;
}

标签:farPos,int,题解,LL,maxv,CF,史莱姆,leq,822
From: https://www.cnblogs.com/cyhforlight/p/16725548.html

相关文章

  • CF 教育场 135 题解
    比赛链接A题ColoredBalls:Revisited(签到)给定\(n\)种颜色的球,其中颜色\(i\)的球的数量是\(cnt_i\),保证\(\sum\limits_{i=1}^ncnt_i\)是奇数。在一次操作中,我......
  • Codeforces Round #822 Div.2 整场题解
    目前还有E,F没有更新。A.SelectThreeSticks直接对\(a\)排序,选出来的木棍一定是相邻三项,都往中间靠更优。B.Bright,Nice,Brilliant最优方案就是每一行第一个......
  • 牛客题解 装进肚子
    链接:https://ac.nowcoder.com/acm/problem/14721来源:牛客网题解作者岛田小雅这道题刚拿到手,就感觉是个很简单(事实证明并不是很简单)的贪心。虽然我不是很会判断贪心的......
  • pycharm打字卡顿问题解决
    问题描述:我在pycharm中使用的远程服务器中的环境,工程也是本机映射到远程环境中,在某次断网以后,再次使用就变得非常卡,具体现象就是我码字要等,整个pycharm就无法点击,过了5秒以......
  • CF627F Island Puzzle.
    容易观察到一次操作是将\(0\)移动到一个相邻的节点上,而且操作可逆转。所以对于不加边的情况方案是唯一的,直接模拟一下看看是不是相等的就好。对于加一条边来说,我们先将......
  • P1347 排序 题解
    题干交了8次,下载了3个测点.....首先这个题,很容易想到用拓扑如果有“X$<$Y”,就建立一条从X到Y的有向边要考虑到,如果排序成立,必须满足入度为0的点只有一个并且出度为0的......
  • P5089 [eJOI2018] 元素周期表 题解
    \(Preface\)主要是想刷点咕值然后就写了一写。。。顺便扔到博客园这边。题解题目传送门这道题嘛..主要还是找性质推规律。拿到题,第一眼:噢噢爆搜啊。第二眼:噢噢贪心啊......
  • P4484题解
    很神奇的状态。。。。。。很难想象这是一个人能在考场上想到的状态。对于一个排列\(p\),设\(f_i\)表示以\(p_i\)结尾的LIS的长度。考虑排列计数的套路令所有元素......
  • Vue中使用benz-amr-recorder插件实现播放amr音频文件以及在线url跨域问题解决
    场景需要做一个Android端和Web端的聊天室,Android端的录音音频文件为.amr格式,除了通过后台server端转码之后,是否可以通过插件在前端直接播放amr的音频文件。benz-amr-rec......
  • CF1089D Distance Sum
    传送门tourist出的绝世好题思路首先,考虑一个范围更广的问题:\[\sum_{u=1}^{n-1}\sum_{v=u+1}^nw_uw_vd(u,v)\]\(w_u\)表示\(u\)的点权,\(d(u,v)\)表示\(u,~v\)......