首页 > 其他分享 >Codeforces Round 876 (Div. 2) 题解 A - D

Codeforces Round 876 (Div. 2) 题解 A - D

时间:2023-06-07 23:45:37浏览次数:57  
标签:const 876 题解 nullptr long int Div include dp

A. The Good Array

题目大意

给定两个整数 \(n\) 和 \(k\),规定一个\(01\)数列为好的的条件是,对于\(1\sim n\)中任意的 \(i\),都有:

  • \(a\) 的前 \(i\) 个元素中至少有 \(\lceil\frac{i}k\rceil\) 个都是 \(1\)。
  • \(a\) 的后 \(i\) 个元素中至少有 \(\lceil\frac{i}k\rceil\) 个都是 \(1\)。

问数列中 \(1\) 的数量的最小可能值。

解题思路

先考虑最简单的情况,\(k\) 取得 \(1\),这样我们的每一个元素都必须为 \(1\)。

如果 \(k\) 不是 \(1\),我们最终得到的序列一定是把 \(1\) 公摊使用的,那么前 \(k\) 个元素当中,只需要第一个元素是 \(1\) 即可,由前后缀的限制我们的数列也一定是对称的,依次类推,我们不难看出,实际上所求的数就是 \(\lceil\frac{n+k-1}{k}\rceil\) 个 \(1\)。

AC Code

#include <iostream>
#include <algorithm>
#include <cstring>
#include <iomanip>
#include <cmath>
#define endl '\n'
#define ios ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr)
using namespace std;
typedef long long LL;

const int N = 1e5 + 10;
const int MOD = 1e9 + 7;

void solve() {
    double n, k;
    cin >> n >> k;
    if (k == 1) {
        cout << n << endl;
        return;
    }
    cout << ceil((n + k - 1) / k) << endl;
}

signed main() {
    ios;
    int T = 1;
    cin >> T;
    while (T--) {
        solve();
    }
}

B. Lamps

题目大意

每个灯有打开,关闭和坏掉三种状态,以及两个参数 \(a\) 和 \(b\)。其中, \(b\) 代表打开一盏灯的得点。\(a\) 代表一种制约关系,当场上打开了 \(x\) 盏灯,那么场上所有 \(a\) 值小于 \(x\) 的灯会同时坏掉,不可以再次操作。

问最后最大得点为多少。

解题思路

首先我们来看看最优情况是怎么样的。

如果存在一个 \(a\) 值很小,比方说是 \(1\),然后 \(b\) 值很大的一盏灯,那么我们肯定会优先开启这盏灯,然后它会坏掉,同时保留这盏灯的得点。

那么我们可以对这些灯按照 \(a\) 值分类,在每一类中对 \(b\) 值由大到小排序,随后只需要暴力找每个值即可。

AC Code

#include <iostream>
#include <algorithm>
#include <cstring>
#define endl '\n'
#define ios ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr)
using namespace std;
typedef long long LL;

const int N = 2e5 + 10;
const int MOD = 1e9 + 7;

void solve() {
    int n;
    LL res = 0;
    cin >> n;
    vector<vector<int>> v(n + 1);
    for (int i = 1; i <= n; ++i) {
        int x, y;
        cin >> x >> y;
        v[x].push_back(y);
    }
    for (int i = 1; i <= n; ++i) {
        std::sort(v[i].begin(), v[i].end(), greater<>());
        for (int j = 0; j < min(i, (int)v[i].size()); ++j) {
            res += v[i][j];
        }
    }
    cout << res << endl;
}

signed main() {
    ios;
    int T = 1;
    cin >> T;
    while (T--) {
        solve();
    }
}

C. Insert Zero and Invert Prefix

题目大意

给定一个\(01\)数列 \(a\),同时初始化一个空\(01\)数列 \(b\),现在需要进行 \(n\) 次操作,每次操作可以选择 \(i \in [0, b.\text{length - 1}]\),将 \(b\) 中 \([0,i]\) 的元素取反,并在第\(i\) 位插入 \(0\),后面的元素不动。问能否操作构造出 \(a\) 数列。

解题思路

从零构造不好做的话我们可以考虑正难则反,考虑逆向情况。

题目转化为删去 \(a\) 中的某个 \(0\),然后将它前面的元素取反。

问能否通过恰好 \(n\) 次操作把 \(a\) 删干净。

我们可以双指针模拟这个过程,因为我们要取得最优情况一定是删去最靠前的 \(0\),这样才能保证每次操作更改的数最少。

需要注意的是我们操作后,数列元素个数有变化,所以他们的编号也有变化,需要使用位置变量来存一下。

AC Code

#include <iostream>
#include <algorithm>
#include <cstring>
#define endl '\n'
#define ios ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr)
using namespace std;
typedef long long LL;

const int N = 1e5 + 10;
const int MOD = 1e9 + 7;

int a[N], res[N];

void solve() {
    int n;
    cin >> n;
    for (int i = 1; i <= n; ++i) {
        cin >> a[i];
    }
    int cnt = 0, pos = 1;
    for (int i = 1; i <= n; ++i) {
        if (!a[i]) {
            res[++cnt] = i - pos;
            for (int j = 1; j <= i - pos; ++j) {
                res[++cnt] = 0;
            }
            pos = i + 1;
        }
    }
    if (cnt != n) {
        cout << "NO" << endl;
        return;
    }
    cout << "YES" << endl;
    for (int i = n; i >= 1; --i) {
        cout << res[i] << ' ';
    }
    cout << endl;
}

signed main() {
    ios;
    int T = 1;
    cin >> T;
    while (T--) {
        solve();
    }
}

D. Ball Sorting

题目大意

有 \(n\) 个彩色球排成一列。这些球被涂成了 \(n\) 种不同的颜色,用数字从 \(1\) 到 \(n\) 表示。从左边数第 \(i\) 个球涂成颜色 \(c_i\)。现在需要重新排列这些球,使得从左边数第 \(i\) 个球的颜色为 \(i\) 。此外,你有 \(k\ge 1\) 个颜色为 \(0\) 的球,可以在重新排列过程中使用。

现在允许如下操作:

  1. 在序列的任意位置放置一个颜色为 \(0\) 的球,同时保持其他球的相对顺序。最多可以执行这个操作 \(k\) 次。
  2. 选择任意一个非零颜色的球同时至少有一个与它相邻的球颜色为 \(0\),将该非零颜色的球移到序列的任意位置,同时保持其他球的相对顺序不变。你可以无限次执行这个操作,但是每次操作你需要支付 \(1\) 个硬币。

操作结束之后颜色为零的球会消失,问排序完成的最小代价是多少。

解题思路

首先看本题的数据范围,最大只到 \(500\),那么 \(O(n^3)\) 的dp可解。

本题实际上是全排列的排序问题,我们颜色为 \(0\) 的球可以让他相邻两边的球归位,而当这个球走了,\(0\) 就会与新的球相邻,那么每个 \(0\) 实际上可以控制一段连续的序列。那么我们可以dp一个LIS(最长上升子序列),同时计算不处于LIS的部分被分成了几段即可。

AC Code

#include <iostream>
#include <algorithm>
#include <cstring>
#define endl '\n'
#define ios ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr)
using namespace std;
typedef long long LL;

const int N = 510;
const int MOD = 1e9 + 7;

int a[N];
int dp[N][N];
LL res[N];

void solve() {
    memset(dp, -0x3f, sizeof dp);
    int n;
    cin >> n;
    for (int i = 1; i <= n; ++i) {
        cin >> a[i];
    }
    a[n + 1] = 0x3f3f3f3f;
    dp[1][0] = 1;
    for (int i = 2; i <= n; i++) {
        dp[i][1] = 1;
    }
    for (int i = 2; i <= n + 1; i++) {
        for (int k = 0; k <= i + 1; k++) {
            for (int j = 1; j < i; j++) {
                if (a[j] < a[i]) {
                    if (j == i - 1) {
                        dp[i][k] = max(dp[i][k], dp[j][k] + 1);
                    } else if (k > 0) {
                        dp[i][k] = max(dp[i][k], dp[j][k - 1] + 1);
                    }
                }
            }
        }
    }
    for (int k = 1; k <= n; ++k) {
        dp[n + 1][k] = max(dp[n + 1][k], dp[n + 1][k - 1]);
        cout << n + 1 - dp[n + 1][k] << ' ';
    }
    cout << endl;
}

signed main() {
    ios;
    int T = 1;
    cin >> T;
    while (T--) {
        solve();
    }
}

标签:const,876,题解,nullptr,long,int,Div,include,dp
From: https://www.cnblogs.com/SanCai-Newbie/p/17464910.html

相关文章

  • Codeforces Round 876 (Div. 2) A-D
    比赛地址A.TheGoodArray题意:定义一个数组是good的要求有:从左往右所有的i,前i个数中至少有[i/k]个数是1从右往左所有的i,前i个数中至少有[i/k]个数是1问good数组对于n而言最少需要多少个1Solution先从左往右填1,直到满足第一个条件,然后从右往左填1,直到满足第二个条件voidso......
  • div元素自适应屏幕大小
    简单介绍一下实现方式(结尾处有代码)1.首先创建一个根元素,将这个跟元素宽高设置为100%,当然,用100vw、100vh也可以,并且将根元素设置为相对定位。2.再创建我们要实现自适应大小的元素,自适应元素我们要给固定的宽高。可以按照常见的屏幕分辨率赋值,1920*1080或者2560*1440。(注:至于为什......
  • 题解:【ARC142D】 Deterministic Placing
    题目链接大佬讲解的太精简了,做点蒟蒻视角的思考补充。下面记摆放棋子的点为黑点,没有摆放棋子的为白点。因为进行无数次操作后,占据节点集合总是唯一,所以黑点一定是在反复横跳;每个位置上只能存在一个黑点,所以每次把移动黑点经过的边拿出来,得到的是若干条不相交的链,并且这些链一定......
  • ABC300F 题解
    前两天忘发出来了,补一下QAQ题目链接题意简述给定一个长度为\(n\)且只包含\(\texttt{o}\)和\(\texttt{x}\)的字符串\(s\)以及正整数\(n\)\(m\)\(k\),令字符串\(T=s^{m}\),求将\(T\)中的\(k\)个\(\texttt{x}\)变成\(\texttt{o}\)之后,\(T\)中连续\(\texttt{o}......
  • P3392 涂国旗 题解
    题目大意题目真的是不说人话......有一个国家的国旗是由一个N*M的方格组成的。如果想要这面国旗合法,就必须满足要求:国旗从上到下必须是白色、蓝色和红色,顺序不能改变。每一种颜色都至少有一行。小a这时候捡到了一块破布,希望你通过涂颜色的方式,把破布成合法的国旗,并且要......
  • 题解 P4556 [Vani有约会]雨天的尾巴 /【模板】线段树合并
    传送门如题目所言,这就是个线段树合并的板子题。题目大意题目描述首先村落里的一共有\(n\)座房屋,并形成一个树状结构。然后救济粮分\(m\)次发放,每次选择两个房屋\((x,y)\),然后对于\(x\)到\(y\)的路径上(含\(x\)和\(y\))每座房子里发放一袋\(z\)类型的救济粮。然......
  • ACM-CodeForces-#685(Div.2)
    A.SubtractorDivide#include<iostream>usingnamespacestd;intmain(){ intT,n; cin>>T; while(T--) { cin>>n; if(n<=3) n--; else n=2+(n&1); cout<<n<<endl; } return0;}B.Non-SubstringSubsequence#in......
  • 【每日一题】LeetCode 786. 第K个最小的素数分数(待补全题解思路)
    题目给你一个按递增顺序排序的数组arr和一个整数k。数组arr由1和若干素数组成,且其中所有整数互不相同。对于每对满足0<i<j<arr.length的i和j,可以得到分数arr[i]/arr[j]。那么第k个最小的分数是多少呢?以长度为2的整数数组返回你的答案,这里answer......
  • 2023上半年(下午)网络工程师试题解析
    2023上半年(下午)网络工程师试题解析试题一(20分)某企业办公楼网络拓扑如图1-1所示。该网络中交换机Switch1-Switch4均是二层设备,分布在办公楼的各层,上联采用千兆光纤。核心交换机、防火墙、服务器部署在数据机房,其中核心交换机实现冗余配置。图1-1问题1(4分)该企业办公网络采用172.16.1......
  • CF1559D2 Mocha and Diana (Hard Version) 题解
    Luogu|Codeforces题意给定两个森林\(A\)和\(B\),均有编号\(1\)到\(n\)的节点,边数分别为\(m_1,m_2\)。现在进行加边操作,但是有两个要求:如果在第一个森林加一条\((u,v)\)的边,第二个森林也要进行同样的操作。反之同理。加边后两个森林依旧是森林。一棵树也是森林。......