Codeforces Round #609 (Div. 1)

Codeforces Round #609 (Div. 1)

A

先保留前 k 位写出当前的答案。如果合法直接输,如果不合法把前 k 位数字 +1 重新写

B

将网格图黑白染色,答案是 cnt=min(num(black),num(white))。可通过二分图匹配或手动构造证明

C

考虑分成两步,1.把这些数移到相邻位置 2.消除逆序对。逆序对数量一定。移到相邻位置可以转化为将空格移动到两边,可以(线段树上)二分找到一个 midmid 左边的往左移更优,右边的往右移更优,然后维护一下区间和就可以计算了(容斥思想)

D

推导:n4 阶的强连通竞赛图存在 (n1) 阶的强连通竞赛子图 —> 对于 n6 做多操作一次 —> 枚举被操作的点,判断是否强连通 证明看这里

如何快速断强连通?不难发现,如果非强连通,缩点后拓扑排序,最后一个 SCC 内的点出度最小。那么我们将点按出度排序,若存在 k<n,前 k 个的出度之和为 (2k),说明这 k 个构成最后一个 SCC 且和其他点无法构成 SCC。直接 sort 单次 nlogn,用个桶排就没有 log 了,总复杂度 O(n2)

下面的是 sortn2logn 的代码

#include <bits/stdc++.h>
using namespace std;
const int N = 2020;
int n, c[N], id[N], k[N]; char a[N][N];
pair<int, int> p[N], pp[N];
int judge () {
    int s = 0;
    for (int i = 1; i < n; ++i) {
        s += pp[i].first; if (s == i * (i - 1) / 2) return 0;
    }
    return 1;
}
signed main() {
    scanf ("%d", &n);
    for (int i = 1; i <= n; ++i) scanf ("%s", a[i] + 1);
    for (int i = 1; i <= n; ++i)
        for (int j = 1; j <= n; ++j) a[i][j] -= '0';
    for (int i = 1; i <= n; ++i)
        for (int j = 1; j <= n; ++j) if (a[i][j]) ++c[j];
    for (int i = 1; i <= n; ++i) p[i] = {c[i], i};
    sort (p + 1, p + n + 1);
    for (int i = 1; i <= n; ++i) id[p[i].second] = i;
    memcpy (pp, p, sizeof (p));
    if (judge ()) return puts ("0 1"), 0;
    if (n <= 6) { // brute
        int mx = 1 << n;
        int mn = 10000, cc = 0;
        for (int i = 0; i < mx; ++i) {
            int num = 0;
            for (int ii = 1; ii <= n; ++ii)
                num += (k[ii] = ((i >> (ii - 1)) & 1)), c[ii] = 0;
            if (num > mn) continue;
            for (int ii = 1; ii <= n; ++ii)
                for (int jj = 1; jj <= n; ++jj)
                    if (a[ii][jj] ^ k[ii] ^ k[jj]) ++c[jj];
            for (int ii = 1; ii <= n; ++ii) pp[ii] = {c[ii], ii};
            sort (pp + 1, pp + n + 1);
            if (judge ()) {
                if (num == mn) ++cc; else mn = num, cc = 1;
            }
        }
        if (mn == 10000) return puts ("-1"), 0;
        for (int i = 1; i <= mn; ++i) cc *= i;
        return printf ("%d %d\n", mn, cc), 0;
    }
    int res = 0;
    for (int i = 1; i <= n; ++i) { // 枚举翻转点
        memcpy (pp, p, sizeof (p));
        for (int j = 1; j <= n; ++j)
            if (a[i][j]) --pp[id[j]].first, ++pp[id[i]].first;
            else --pp[id[i]].first, ++pp[id[j]].first;
        sort (pp + 1, pp + n + 1); res += judge ();
    }
    return printf ("1 %d\n", res), 0;
}

E

对于“边权递增”的条件可以建一张新图:以边为节点,相邻的边之间小的向大的连边。要求的就是这张 DAG 上的可达点数量

根据定义,如果是树,直接一遍 dp 简单的求和就是答案。但仙人掌中的环会使答案产生重复。幸运的是,重复的地方只可能是环上的最小边,因为只有它可以往两个方向在环上走。更进一步,只有这个环上最小边往最大边走的两条路径都递增才会重复(两条路径可以在最大值处相交)。那么可以预处理出每个环是否有重复

具体做法:从大到小考虑每条边(DAG 的拓扑序),边权的 dp 是两个端点之和,如果这个环会产生重复且此边为最小就要减去最大边的 dp(即之后重合的部分)。点权的 dp 值亦在此过程中得出

本文作者:-敲键盘的猫-

本文链接:https://www.cnblogs.com/whx666/p/609-div1.html

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   -敲键盘的猫-  阅读(42)  评论(0编辑  收藏  举报
编辑推荐:
· Linux glibc自带哈希表的用例及性能测试
· 深入理解 Mybatis 分库分表执行原理
· 如何打造一个高并发系统?
· .NET Core GC压缩(compact_phase)底层原理浅谈
· 现代计算机视觉入门之:什么是图片特征编码
阅读排行:
· 手把手教你在本地部署DeepSeek R1,搭建web-ui ,建议收藏!
· Spring AI + Ollama 实现 deepseek-r1 的API服务和调用
· 数据库服务器 SQL Server 版本升级公告
· C#/.NET/.NET Core技术前沿周刊 | 第 23 期(2025年1.20-1.26)
· 程序员常用高效实用工具推荐,办公效率提升利器!
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起