ICode9

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

CF Round 789 Div2 题解

2022-05-10 20:04:40  阅读:118  来源: 互联网

标签:return int 题解 789 CF leq solve 操作 --


比赛链接

A题 Tokitsukaze and All Zero Sequence(思维)

给定一个长度为 \(n\) 的数列 \(\{a_n\}\)。

我们可以进行若干次操作,每次操作都选定两个位置 \(i.j\),随后:

  1. 若 \(a_i=a_j\),可以选择将 \(a_i\) 或 \(a_j\) 变为 0
  2. 若 \(a_i\not=a_j\),可以选择将 \(a_i,a_j\) 都变为 \(\min(a_i,a_j)\)

问至少需要多少次操作,可以使得数列变为全空?

共 \(T(T\leq 10^3)\) 组数据,每组数据中 \(2\leq n\leq 100,0\leq a_i\leq 100\)

每次操作至多将一个非 0 的数变为 0,所以我们在数列中有 0 的情况下,输出 \(n\) 减去 0 的数量即可。

当所有数都不是 0 的时候,那么必须先把一个数变成 0,随后执行上面的操作:

  1. 存在两个相同的数字,先将其中一个变成 0,然后依次把其他的数变为 0即可,总次数 \(n\)
  2. 所有数各不相同,那么先执行一个操作2,等到他俩相同后就执行上面的流程,总次数 \(n+1\)

判断每个数是否相同,可以开一个桶,也可以直接 set 或者排序处理。

#include <bits/stdc++.h>
using namespace std;
const int N = 210;
int n, a[N], v[N];
int solve() {
    cin >> n;
    for (int i = 1; i <= n; ++i)
        cin >> a[i];
    memset(v, 0, sizeof(v));
    for (int i = 1; i <= n; ++i)
        ++v[a[i]];
    if (v[0] > 0) return n - v[0];
    else {
        for (int i = 0; i <= 100; ++i)
            if (v[i] > 1) return n;
        return n + 1;
    }
}

int main()
{
    int T;
    cin >> T;
    while (T--) cout << solve() << endl;
    return 0;
}

B1题 Tokitsukaze and Good 01-String (easy version)(贪心)

给定一个长度为 \(n\)(必然是偶数),仅包含 01 的字符串。

现在可以执行操作,每次可以选择将某一位进行变换(01互换)。

问,至少要执行多少次操作,才能使得数列符合性质?(性质直接看原题面)

\(2\leq n \leq 2*10^5\)

我们先把他们划分下来,随后奇数段记为 1,偶数段记为 0。

从前扫到后,每当该段为 1 的时候,就要花费 1 的代价使得这一段变为 0,下一段互换,最后输出代价和即可,复杂度 \(O(n)\)。

#include <bits/stdc++.h>
using namespace std;
const int N = 200010;
int n;
char s[N];
int vec[N];
int solve() {
    //read & init
    scanf("%d%s", &n, s + 1);
    int tot = 0, cnt = 1;
    for (int i = 2; i <= n; ++i)
        if (s[i] == s[i - 1]) ++cnt;
        else vec[++tot] = cnt, cnt = 1;
    vec[++tot] = cnt;
    //solve
    int res = 0;
    for (int i = 1; i <= tot; ++i)
        if (vec[i] % 2) vec[i]--, vec[i + 1]++, ++res;
    return res;
}

int main()
{
    int T;
    cin >> T;
    while (T--) printf("%d\n", solve());
    return 0;
}

C题 Tokitsukaze and Strange Inequality(前缀和,枚举优化)

给定一个长度为 \(n\) 的排列 \(\{p_n\}\),问存在多少四元组 \((a,b,c,d)\),满足 \(1\leq a<b<c<d\leq n,p_a<p_c,p_b>p_d\) ?

\(1\leq n \leq 5000\)

我们考虑枚举 \(b,c\),那么就变成了维护 \([1,b-1],[c+1,n]\) 这两个区间:每次 \(O(1)\) 查询 \([1,b-1]\) 上有多少数小于 \(p_c\),\([c+1,n]\) 上有多少数小于 \(p_b\)。

考虑到至多只有 \(n\) 种不同的数(题目给定了排列,都不用离散化),所以我们开一个数组 \(f_{i,j}\),表示前 \(i\) 个数中小于 \(j\) 的元素个数。同样的,\(g_{i,j}\) 表示后 \(i\) 个数中小于 \(j\) 的元素个数。

随后对于每个枚举的 \(b,c\),根据乘法原理,给答案加上 \(f_{b-1,p_c}*g_{c+1,p_b}\) 即可。

时空复杂度均为 \(O(n^2)\),有点小紧。

本题有一个类似的姊妹题:CF1400D Zigzags

#include <bits/stdc++.h>
using namespace std;
#define LL long long
const int N = 5010;
int n, p[N];
int f[N][N], g[N][N];
LL solve() {
    cin >> n;
    for (int i = 1; i <= n; ++i)
        cin >> p[i];
    for (int i = 1; i <= n; ++i)
        f[0][i] = g[n + 1][i] = 0;
    for (int i = 1; i <= n; ++i)
        for (int j = 1; j <= n; ++j)
            f[i][j] = f[i - 1][j] + (p[i] < j);
    for (int i = n; i >= 1; i--)
        for (int j = 1; j <= n; ++j)
            g[i][j] = g[i + 1][j] + (p[i] < j);
    LL res = 0;
    for (int b = 1; b < n; ++b)
        for (int c = b + 1; c < n; ++c)
            res += f[b - 1][p[c]] * g[c + 1][p[b]];
    return res;
}

int main()
{
    int T;
    cin >> T;
    while (T--) cout << solve() << endl;
    return 0;
}

标签:return,int,题解,789,CF,leq,solve,操作,--
来源: https://www.cnblogs.com/cyhforlight/p/16255006.html

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

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

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

ICode9版权所有