Loading

APIO2025构造题讲课补题

APIO2025构造题讲课补题

第一类调整法

先给出一个“比较正确”的解法,再调整它。

[IOI 2020] 网络站点

先考虑用入栈序标号,发现不能确定 \(s\) 最后一个子树和 \(s\) 子树外的情况。可以发现这时 \(s\) 点本身的编号没有使用,可以想到用 \(s\) 本身的编号区别上述情况,这时只要把 \(s\) 的标号改为出栈序即可。

为了实现这个目的,可以考虑每层入栈、出栈序交替编号。所以还要考虑反过来,\(s\) 是入栈序,其他节点是出栈序的情况,发现这是可以的。

感觉这个技巧可以放进传统题中。

CF1930H. Interactive Mex Tree

由于点权是排列,路径上点的 \(\text{mex}\) 等于路径外的点的 \(\min\)

同样考虑一个序列是入栈序,设 \(x,y\)\(lca\)\(z\) \(z\to y\) 路径上 \(z\) 的儿子为 \(s_y\),发现我们不能覆盖所有入栈时间在 \([in[z],in[x]]\) 之间,和入栈时间在 \([in[s_y],in[y]]\) 之间的非链上的节点,但是这些节点的出栈序一定在 \((1,out[x])\)\((out[s_x],out[y])\) 上,且不包含链上的节点,于是就做完了。

这个5个区间覆盖排除链的技巧完全可以用在传统题上。以避免数链剖分,少一个\(\log\)

第二类调整法

题目限制“恰好为 k”,那么可以先不管这个条件给出“最大的构造方法”和“最小的构造方法”,证明之间的数都可以取到,然后逐步调整为 \(k\)

更抽象地说,这种思路实际上是估计“最好情况”和“最坏情况”,依此来推出所有“中间情况”。所以“恰好为k”这样的条件并不是必要的。

CF1311E. Construct the Binary Tree

  • 点到根距离和最小:完全二叉树

  • 点到根距离和最大:链

  • 逐个将链尾移动到父亲,可以逐步将答案减一,最终达到最小值。

调整即可。

QOJ10102 Puzzle: Nurikabe

  • 白色点最多:铺满

  • 白色点最少:

    先给出答案(可以考虑一个构造,也可以直接分析),再考虑能否取到。

    不妨设 \(n\le m\)

    • \(n=1\)\(\min(y,m-y+1)\),因为要连通

    • \(n=2\)\(m-2+[y=1\lor y=m]\)

    • \(n\ge 3\) 时,考虑下图:

      考虑条件3可以转化为每个红点旁边的4个格子中必须有白色格子。一个大小为 \(k\) 的连通块最多覆盖 \(2k+2\) 个红点,所以要求:\(2k+2\ge (n-1)(m-1)\)

      • \(n,m\) 都是偶数,\(k\ge\frac{(n-1)(m-1)+1}{2}-1\)

      • 否则 \(k\ge \frac{(n-1)(m-1)}2-1\)

      发现当 \(x,y\) 不在边上的时候一定可以取等,在边上时答案 \(+1\),在角落答案 \(+2\)

  • 通过不断将黑点变为白点,可以取到上下界中所有情况。

然而作为构造题还要知道如何构造,先构造最小值,然后BFS扩展到 \(z\)

  • \(\min(n,m)\le 2\):特判构造,简单

  • \(n\)偶:选择第 \(\max(2,\min(n-1,x))\) 行,再正常选择其他列,如果 \(m\) 是偶数特殊处理最后一列。

  • \(n\)奇:选择第 \(\max(2,\min(m-1,y))\) 列,再正常选择其他行

CF1770H.Koxia Mahiru and Winter Festival

难以构造的方案

增量法

假设已经有了一个构造方法,将它扩展到更大的情况。

求竞赛图一条哈密顿路径

考虑增量,假设现在对于 \(1\sim n-1\) 的点有了构造方案,考虑加入点 \(n\)

假设这条路径的点是 \(p_1\sim p_{n-1}\),分类讨论:

  • \(n\to p_1\)\(p_{n-1}\to n\) 的边,可以直接加在链头/尾

  • 否则一定有边 \(p_1\to n\to p_{n-1}\),此时一定存在一个 \(i\) 使得存在边 \(p_{i}\to n\to p_{i+1}\),将 \(n\) 放入即可。

P6644 [CCO 2020] Travelling Salesperson

这道题思路与上一道题一样,假设现在有了一个前 \(n-1\) 个点的 \(p_1\to p_{n-1}\) 的路径,设其先红后蓝,且在 \(p_i\) 切换颜色。

  • 如果 \((p_i,n)\) 是蓝边,则插入路径 \(p_{i-1}\to n\to p_i\) 不论 \((p_{i-1},n)\) 的颜色都是正确的。

  • 否则插入路径 \(p_i\to n\to p_{i+1}\) 同理一定是正确的。

“从每个点出发"就求 \(n\) 遍,复杂度 \(\mathcal O(n^2)\)。需要注意一点细节,比如颜色全部一样时,为了不改变起点,应该将加入的放到末尾。

规约法

找到构造目标的某个部分,将它先构造掉,然后就只需考虑删掉它之后的情况。

CF1019C. Sergey's problem

增量规约综合。

证明存在性:发现题目没有让我们输出无解所以得证。考虑如果存在一个非关键点 \(y\) 使得距离其最近的关键点 \(x\)\(y\) 的距离 \(\ge 3\),则在距离 \(y\)\(1\) 的位置放置一个关键点一定不会使得两个关键点相邻。所以存在。

考虑增量法,每次加入一个点 \(x\),分类讨论:

  • 如果这个点有入点被选择,那么不选 \(x\)

  • 否则如果这个点有没出点被选择,选择 \(x\)

  • 否则如果这个点有出点被选择,理应不选,但又没法保证自己被 \(2\) 步到达,难以处理。

为了避免这种情况,我们不去增量而是规约。

每次考虑一个节点 \(x\),如果已经被删除则不考虑,否则将 \(x\)\(x\) 所有出点一起删除,接着计算子问题。当得到子问题的一个解时,分类讨论:

  • 如果有入点被选,则不选 \(x\),这个入点已经可以2步到达 \(x\)\(x\) 出点。

  • 否则,选择 \(x\) ,由于其出点全部被删除,不会有上述第 \(3\) 种情况。

做完了,复杂度 \(\mathcal O(n)\)

这道题的传统规约法不同,不一定需要”将它先构造掉“,而是先删除部分,根据子问题的解法“增量”。这种规约本质是一种增量。

#include<bits/stdc++.h>
#define int long long
#define loop(i,a,b) for(int i=a;i<=b;i++)
#define pool(i,a,b) for(int i=a;i>=b;i--)
#define pb push_back
const int NN=1e6+5;
using namespace std;
int n,m,cnt;
vector<int> ed[NN];
bool del[NN],chos[NN];
signed main(){
    cin>>n>>m;
    loop(i,1,m){
        int a,b;cin>>a>>b;
        ed[a].pb(b);
    }
    loop(x,1,n){
        if(del[x])continue;
        chos[x]=1;
        for(int y:ed[x])del[y]=1;//先删除 
    }
    pool(x,n,1){//回溯 
        if(!chos[x])continue;
        cnt++;
        for(int y:ed[x])chos[y]=0;
    }
    cout<<cnt<<"\n";
    loop(i,1,n)if(chos[i])cout<<i<<" ";
    return 0;
}

P10871 [COTS 2022] 皇后 Kraljice - 洛谷

什么神器COTS2022Day1,全是构造题。

纯手玩,各种构造方法纯手玩。

矩阵可以考虑从外向内递归 \(n\to n-2\) 然后手玩出构造方法。

posted @ 2025-06-05 19:30  lupengheyyds  阅读(24)  评论(0)    收藏  举报