Skip to content

泉州一中信息学Blog

信息学奥赛技术分享博客

  • 登录
  • 小学oj
  • 中学oj
  • 测试页面1
  • Toggle search form

GDNOJ – DAY 6

Posted on 2025年7月31日 By 张, 高畅 GDNOJ – DAY 6无评论

怀疑教学内容日渐趋近于宇航员选拔的方向了。

是我的错觉吗。

李超线段树

总之是维护若干条直线/线段的结构。

似乎目前例题比较少,只有两个,不过和DP结合优化的题目应该不会少。

二分图最大匹配

板子请移步P3386,不再赘述。

几个有意思的题目:

CF1139E:
删除边毕竟是不容易的,考虑倒着做来处理,变成加边。

我们可以令二分图左侧为答案(值域),右侧为对应社团。

注意到答案单调不减,因此维护当前答案,每次暴力做匹配,如果找到增广路,答案++,继续以上过程。

由于这样做保证了进行匹配的次数不会很多,所以能过。

注意,有多次进行匹配的情况,访问数组可以与时间戳进行比对,无需在最开始全部赋零以减少复杂度。

#include<bits/stdc++.h>
using namespace std;
const int N = 5005;
int n, m, d, p[N], c[N], timestamp;
int h[N], e[N], ne[N], idx;
int match[N], st[N];
int id[N], unr[N], res[N]; 
void add(int a, int b){e[idx] = b, ne[idx] = h[a], h[a] = idx++;}
int find(int u)
{
    for (int i = h[u]; ~i; i = ne[i])
    {
        int j = e[i];
        if (st[j] != timestamp)
        {
            st[j] = timestamp;
            if (match[j] == -1 || find(match[j]))
            {
                match[j] = u;
                return 1;
            }
        }
    }
    return 0;
}
int main()
{
    memset(h, -1, sizeof h);
    scanf("%d%d", &n, &m);
    for (int i = 1; i <= n; i ++)scanf("%d", &p[i]);
    for (int i = 1; i <= n; i ++)scanf("%d", &c[i]);
    scanf("%d", &d);
    for (int i = 1; i <= d; i ++)
    {
        scanf("%d", &id[i]);
        unr[id[i]] = 1;
    }
    for (int i = 1; i <= n; i ++)
    {
        if (!unr[i])add(p[i], c[i]);
    }
    memset(match, -1, sizeof match);
    for (int i = d, mex = 0; i; i --)
    {
        timestamp ++;
        while (find(mex))
        {
            mex ++;
            timestamp ++;
        }
        res[i] = mex;
        add(p[id[i]], c[id[i]]);
    }
    for (int i = 1; i <= d; i ++)printf("%d\n", res[i]);
    return 0;
}

CF387D
答案大概是 O(n ^ 3) 级别的,而匹配一次仅仅需要 O(n ^ 2),因此枚举这个中心点。

最开始统计每个点的出度和入度,注意自环仅仅只计算一次。

对于中心点,需要的答案是 2n – 1 – d_{center}

之后对于非中心点做二分图最大匹配,相当于利用现在所能利用的边。

对于非中心点,需要一个出度,一个入度,大抵长成一个环的样子。

我们设最大匹配的结果是 p。

首先删除无用边的答案是 m – d_{center} – 1 的。

加入新边所需要的答案是 n – 1 – p 的。

然后做完了。

#include<bits/stdc++.h>
using namespace std;
const int N = 505, M = 1005;
int n, m, res = 1e9;
int h[N], e[M], ne[M], idx;
int match[N], st[N], timestamp;
int d[N];
void add(int a, int b){e[idx] = b, ne[idx] = h[a], h[a] = idx++;}
int find(int u, int center)
{
    for (int i = h[u]; ~i; i = ne[i])
    {
        int j = e[i];
        if (j != center && st[j] != timestamp)
        {
            st[j] = timestamp;
            if (!match[j] || find(match[j], center))
            {
                match[j] = u;
                return 1;
            }
        }
    }
    return 0;
}
int main()
{
    memset(h, -1, sizeof h);
    scanf("%d%d", &n, &m);
    for (int i = 1, a, b; i <= m; i ++)
    {
        scanf("%d%d", &a, &b);
        add(a, b);
        d[a] ++;
        if (a != b)d[b] ++;
    }
    for (int center = 1; center <= n; center ++)
    {
        int ans = 2 * n - 1 - d[center], matches = 0;
        memset(match, 0, sizeof match);
        for (int i = 1; i <= n; i ++)
        {
            if (i != center)
            {
                timestamp ++;
                matches += find(i, center);
            }
        }
        ans += m - d[center] - matches;
        ans += (n - 1) - matches;
        res = min(res, ans);
    }
    printf("%d", res);
    return 0;
}

二分图最大权匹配

在此之前可以先了解 BFS 进行增广路求解过程。

KM 算法仅仅支持完美匹配,即两侧点数相同。

但是我们可以私自在较小的点集中补点,并自己新建虚边。

整个算法流程通俗理解就是一部分不断降低要求,另一部分不断提高要求,以寻找最大权匹配的过程。

注意此时如果使用 dfs 求增广路,可能出现多次搜索无用边降低效率,复杂度最高高达 O(n ^ 4)。

因此使用 bfs 求。但是我并不知道LUOGU过了为什么HDU上过不了。

#pragma GCC optimize(3)
#include<bits/stdc++.h>
using namespace std;
const int N = 305;
const int INF = 0x3f3f3f3f;
int n, match[N], pre[N];
int G[N][N], w1[N], w2[N], slack[N];
int st[N];
void bfs(int S)
{
    memset(pre, 0, sizeof pre);
    memset(st, 0, sizeof st);
    memset(slack, 0x3f, sizeof slack);
    int cur = 0;
    match[cur] = S;
    do
    {
        int d = INF;
        int u = match[cur], newcur = 0;
        st[cur] = 1;
        for (int i = 1; i <= n; i ++)
        {
            if (st[i])continue;
            if (slack[i] > w1[u] + w2[i] - G[u][i])
            {
                slack[i] = w1[u] + w2[i] - G[u][i];
                pre[i] = cur;
            }
            if (slack[i] < d)
            {
                d = slack[i];
                newcur = i;
            }
        }
        for (int i = 0; i <= n; i ++)
        {
            if (st[i])
            {
                w1[match[i]] -= d;
                w2[i] += d;
            }
            else slack[i] -= d;
        }
        cur = newcur;
    }
    while (match[cur]);
    while (cur)
    {
        match[cur] = match[pre[cur]];
        cur = pre[cur];
    }
}
int KM()
{
    for (int i = 1; i <= n; i ++)bfs(i);
    int res = 0;
    for (int i = 1; i <= n; i ++)res += G[match[i]][i];
    return res;
}
int main()
{
    while(~scanf("%d", &n))
    {
        memset(match, 0, sizeof match);
        memset(w1, 0, sizeof w1);
        memset(w2, 0, sizeof w2);
        for (int i = 1; i <= n; i ++)
        {
            for (int j = 1; j <= n; j ++)scanf("%d", &G[i][j]);
        }
        printf("%d\n", KM());
    }
    return 0;
}
训练日志

文章导航

Previous Post: 中山集训7.31
Next Post: 21 Days Training // Day 6

发表回复 取消回复

要发表评论,您必须先登录。

2025年 12月
一 二 三 四 五 六 日
1234567
891011121314
15161718192021
22232425262728
293031  
« 8月    

2024常州 Class Classic OI Problems Contest cqr的长乐集训2023 CZYZ LOC New Game NOI NOIP Password Protected PM_PK Preview Problems Retrospect Selfmade Qusetion STL The end Training Uneasy Problem 蒟蒻 通报

  • 训练日志
  • 链表
  • 入门
  • 模拟
  • dfs序
  • 并查集
  • spfa
  • 最小割
  • 矩阵树定理
  • 仙人掌
  • BSGS
  • 凸包
  • 回文自动机
  • 递推与动归
  • 堆
  • 莫队算法
  • ST表
  • Treap
  • 树套树
  • 可持久化线段树
  • 初赛
  • 搜索
  • 贪心
  • 深度优先搜索
  • 欧拉图
  • dijkstra
  • 费用流
  • 哈夫曼树
  • kruskual
  • 置换
  • 旋转卡壳
  • KMP
  • 区间动归
  • STL
  • 链表
  • 可并堆
  • sply
  • 主席树
  • 可持久化字典树
  • 算法
  • 动态规划
  • 构造
  • 广度优先搜索
  • 最短路
  • floyd
  • 最大流
  • 虚树
  • prim
  • 筛法
  • 半平面交
  • 字典树
  • 背包动归
  • 基础数据结构
  • 分块
  • 线段树
  • 替罪羊树
  • K-DTree
  • 图论
  • 二分法
  • 迭代搜索
  • 拓扑排序
  • 有上下界网络流
  • 生成树
  • 快速幂
  • 后缀数组
  • 树形动归
  • 哈希表
  • 中级数据结构
  • 平衡树
  • 可持久化数据结构
  • 数据结构
  • 三分法
  • 启发式搜索
  • 图的连通
  • 点分治
  • 博弈论
  • AC自动机
  • 状压动归
  • 单调栈
  • 树状数组
  • 高级数据结构
  • OI资料
  • 数学
  • 高精度
  • 差分约束
  • 树上倍增
  • 素数测试
  • 后缀自动机
  • 数位动归
  • 单调队列
  • 新闻
  • 几何
  • 随机化
  • 二分图染色
  • 树链剖分
  • 欧拉函数
  • manacher
  • 斜率优化
  • 离线处理
  • 信息学奥赛学长风采
  • 字符串
  • 二分图匹配
  • prufer编码
  • 卡特兰数
  • 密码学
  • 决策单调
  • 赛后总结
  • 其他
  • 2-SAT
  • 最近公共祖先
  • 矩阵乘法
  • 记忆化搜索
  • 网络流
  • Link cut tree
  • 排列组合
  • 树
  • 高斯消元
  • 乘法逆元
  • 容斥原理
  • 调和级数
  • 概率与期望
  • 模线性方程组
  • 莫比乌斯反演
  • 快速傅里叶变换
  • 扩展欧几里德
  • 最大公约数与最小公倍数

近期文章

  • 中山纪念中学 Day21
  • 中山集训8.15 LAST DAY+集训小结
  • GDNOJ – DAY 18
  • 中山8.14
  • 2025暑假中山集训Day20——8.14

近期评论

归档

  • 2025年8月
  • 2025年7月
  • 2025年2月
  • 2025年1月
  • 2024年11月
  • 2024年10月
  • 2024年9月
  • 2024年8月
  • 2024年7月
  • 2024年3月
  • 2024年2月
  • 2024年1月
  • 2023年12月
  • 2023年11月
  • 2023年10月
  • 2023年9月
  • 2023年8月
  • 2023年7月
  • 2023年3月
  • 2023年2月
  • 2023年1月
  • 2022年12月

Copyright © 2025 泉州一中信息学Blog.

Powered by PressBook WordPress theme