CF Round 810 Div2 题解

比赛链接

A题 Perfect Permutation

给定正整数 \(n\),要求构造出一个长度为 \(n\) 的排列 \(\{p_n\}\),满足该排列的价值最小,并输出。

排列的价值:满足 \(i|p_i\)\(i\) 的个数。

\(T\leq 10^4,n,\sum n\leq 10^5\)

学数论的时候,接触过一个性质:\(\gcd(a-1,a)=1(a>1)\)

那么,直接构造类似 \((2,3,4,5,1)\) 的排列就行了。

#include<bits/stdc++.h>
using namespace std;
void solve() {
    int n;
    scanf("%d", &n);
    for (int i = 2; i <= n; ++i) printf("%d ", i);
    printf("1\n");
}
int main()
{
    int T;
    cin >> T;
    while (T--) solve();
    return 0;
}

B题 Party

已知有 \(n\) 个人,不邀请第 \(i\) 个人参加宴会的话,会增加 \(a_i\) 的不满意度。

\(n\) 个人之间有 \(m\) 对关系,如果参加宴会的某两个人存在关系,那么他们就会很高兴,然后一起吃一块蛋糕。(一个人可以吃多个蛋糕,例如 1 和 2,3,4,5 都有关系,那么 1 就会吃 4 次蛋糕)。

不过,我们希望最后吃掉的蛋糕数量为偶数,问在此基础上,怎样使得不满意度最小?

\(T\leq 10^4,n,m,\sum n,\sum m\leq 10^5,0\leq a_i\leq 10^4\)

简化一下:给定一张 \(n\)\(m\) 边的点带权无向图,要求删除几个点(以及和它们相邻的边),使得剩下的图中,边的数量为偶数,在此基础上要求删除的点的点权和最小。

  1. \(m\) 为偶数时,不需要删除任何点,直接输出 0 即可

  2. \(m\) 为奇数时,我们统计图中的奇度点数量为 \(x\),偶度点数量为 \(y\)

    1. \(x=0\) 时,我们需要删除一个偶度点,那么和他相连的所有点都变成了奇度点,挑一个最小的删除即可。

      因此,我们直接枚举要删哪两个点即可。显然,不存在其他更优的方案。

    2. \(x>0\) 时,我们可以采取上面的策略,也可以直接挑一个奇度点删掉。

总复杂度为 \(O(n+m)\)

#include<bits/stdc++.h>
using namespace std;
const int N = 100010;
int n, m, a[N], u[N], v[N], d[N];
int solve()
{
    scanf("%d%d", &n, &m);
    memset(d, 0, sizeof(int) * (n + 1));
    for (int i = 1; i <= n; ++i) scanf("%d", &a[i]);
    for (int i = 1; i <= m; ++i) {
        scanf("%d%d", &u[i], &v[i]);
        d[u[i]]++, d[v[i]]++;
    }
    if (m % 2 == 0) return 0;
    int ans = 1e9 + 10;
    for (int i = 1; i <= n; ++i)
        if (d[i] % 2 == 1) ans = min(ans, a[i]);
    for (int i = 1; i <= m; ++i) {
        int x = u[i], y = v[i];
        if (d[x] % 2 == 0 && d[y] % 2 == 0)
            ans = min(ans, a[x] + a[y]);
    }
    return ans;
}
int main() {
    int T;
    cin >> T;
    while (T--) printf("%d\n", solve());
    return 0;
}

C题 Color the Picture

给定一个 \(n\)\(m\) 列的方格矩阵,初始状态下所有方格都没有颜色。

现在给定 \(k\) 种不同的颜料,但是第 \(i\) 种颜料至多能涂 \(a_i\) 个方块。

问,能否找到一种涂色方式,使得所有方格都被涂上颜色,且任意一块的周围,至少三个方格的颜色和其相同?

“周围”的定义:如果两个方格的坐标分别为 \((x_1,y_1),(x_2,y_2)\),且共享同一条边(具体定义可以参照原题面,简单来说,就是最上一列和最下一列,以及最左最右一列相邻)。

\(3\leq n,m\leq 10^9,1\leq a_i\leq 10^9,k\leq 10^5\)

参照题目样例,发现:如果一个颜色要满足要求(且不妨碍他人),那么他应该单独占据连续的 \(2\) 行/列或者更多。(两个都要做一下,我这里就直接按照填列的方式来过一遍流程,跟样例的方式一样)

我们计算出每种颜料能够涂多少列,然后将大于等于 2 的找出来涂就行了。但是要注意,为了避免出现 2 2 2 2 1 这种情况,所以需要我们从小到大选颜料(排个序),如果发现涂完了后只剩一列,那么就自己少一列;如果自己只有两列,那么就跳过这个颜色,换下一个来涂。最终根据涂色状况来判断能不能达成目标,复杂度 \(O(k\log k)\)

#include<bits/stdc++.h>
using namespace std;
const int N = 100010;
int n, m, k, a[N];
bool check(int n, int m) {
    int cnt = m;
    for (int i = 1; i <= k; i++) {
        int t = a[i] / n;
        if (t < 2) continue;
        if (cnt <= t) return true;
        else if (cnt - t == 1) {
            if (t == 2) continue;
            else cnt = 2;
        }
        else cnt -= t;
    }
    return false;
}
bool solve() {
    scanf("%d%d%d", &n, &m, &k);
    for (int i = 1; i <= k; ++i)
        scanf("%d", &a[i]);
    sort(a + 1, a + k + 1);
    if (check(n, m)) return true;
    return check(m, n);
}
int main() {
    int T;
    cin >> T;
    while (T--) puts(solve() ? "YES" : "NO");
    return 0;
}
posted @ 2022-07-25 21:00  cyhforlight  阅读(61)  评论(0编辑  收藏  举报