首页 > 其他分享 >CF1630F-最小割、Dilworth定理

CF1630F-最小割、Dilworth定理

时间:2024-08-27 17:37:59浏览次数:12  
标签:return idx int auto 定理 CF1630F back push Dilworth

link:https://codeforces.com/contest/1630/problem/F

给你一个由 \(n\) 个顶点组成的无向图,编号从 \(1\) 到 \(n\) ,其中顶点 \(i\) 的值为 \(a_i\) ,所有值 \(a_i\) 都是不同的。如果 \(a_u\) 整除 \(a_v\) ,则两个顶点 \(u\) 和 \(v\) 之间存在一条边。当删除一个顶点时,也就删除了与之相连的所有边。
问最少删几个点使得得到的是二分图。
\(1\leq n\leq 5\times 10^4\).


首先整除是个偏序关系,它比DAG的性质来得强:如果 \(a|b,b|c\) 则必有 \(a|c\),翻译过来就是如果有边 \(u\to v,v\to w\) 则必有 \(u\to w\),这样就出现了一个三元环。
换言之如果把无向边改成有向边(例如大的连小的),如果要得到二分图,那么不能有长度 \(\geq 2\) 的链,即每条链最长是 \(1\),也就是说每个点要么只有入度,要么只有出度,此时也一定是二分图。

那么就能把点分成两类,拆点:\(u\) 表示 \(u\) 只有出度,\(u'\) 表示只有入度,\((u,u')\) 连一条无向边表示两个事件不能同时发生。如果原图有 \(u\to v\) 的边,则 \(u,v\) 明显也不能同时有出度(这意味着 \(v\) 有入度),因此有 \((u,v)\) 的边,类似地会有 \((u',v'),(u',v)\) 这些边

这样得到了一张新的二分图,图上任意一条边表示两端的事件不能同时发生,如果要保留最多的点,相当于求最大独立集,即求最大的点集 \(V'\subset V\), 使得 \(V'\) 内任意两个点之间无边。

注意到 这张二分图是可以变成偏序集的:

\(ans=n-\) 留下的最多点

留下的最多点=这张图的最大独立集=补图的最长链,补图的边数太多了,而根据Dilworth定理,偏序集上的最长链=补图的最小边覆盖,因此图的最大独立集=最小边覆盖,对这张DAG求个最小路径覆盖=拆点后点数-最小割。

#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define endl '\n'
#define fastio ios_base::sync_with_stdio(false);cin.tie(0);cout.tie(0)
using namespace std;
typedef pair<int,int> pii;

template<class T>
struct Dinic{//ind from 0 to n-1
    struct Edge{
        int to;T cap;
        Edge(int to,T cap):to(to),cap(cap){}
    };
    int n;
    vector<Edge> E;
    vector<vector<int>> G;
    vector<int> cur,h;

    Dinic(int n=0){init(n);}
    void init(int n){
        this->n=n;
        E.clear();
        cur.resize(n);
        h.resize(n);
        G.assign(n,{});
    }
    void addEdge(int u,int v,T c){
        G[u].push_back(E.size());E.emplace_back(v,c);
        G[v].push_back(E.size());E.emplace_back(u,0);
    }
    bool bfs(int s,int t){
        h.assign(n,-1);
        queue<int> que;
        h[s]=0;
        que.push(s);
        while(!que.empty()){
            const int u=que.front();
            que.pop();
            for(auto i:G[u]){
                auto [v,c]=E[i];
                if(c>0&&h[v]==-1){
                    h[v]=h[u]+1;
                    if(v==t)return true;
                    que.push(v);
                }
            }
        }
        return false;
    }
    T dfs(int u,int t,T f){
        if(u==t)return f;
        auto r=f;
        for(int &i=cur[u];i<(int)G[u].size();i++){
            const int j=G[u][i];
            auto [v,c]=E[j];
            if(c>0&&h[v]==h[u]+1){
                auto a=dfs(v,t,std::min(r,c));
                E[j].cap-=a;
                E[j^1].cap+=a;
                r-=a;
                if(r==0)return f;
            }
        }
        return f-r;
    }
    T work(int s,int t){
        T ans=0;
        while(bfs(s,t)){
            cur.assign(n,0);
            ans+=dfs(s,t,std::numeric_limits<T>::max());
        }
        return ans;
    }
};
int main(){
    fastio;
    constexpr int N=5e4;
    constexpr int INF=std::numeric_limits<int>::max();
    int tc;cin>>tc;
    vector<vector<int>> divisor(N+5);
    rep(i,1,N)for(int j=i+i;j<=N;j+=i)divisor[j].push_back(i);

    while(tc--){
        int n;cin>>n;
        vector<pii> E;
        auto work=[&](int n)->int{
            int st=2*n,ed=2*n+1;
            Dinic<int> flow(ed+1);
            for(auto [u,v]:E)flow.addEdge(u,v+n,1);
            rep(i,0,n-1){
                flow.addEdge(st,i,1);
                flow.addEdge(i+n,ed,1);
            }
            return n-flow.work(st,ed);
        };
        set<int> S;
        map<int,int> idx;
        rep(i,0,n-1){
            int x;cin>>x;
            S.insert(x);
            idx[x]=i;
            E.push_back({idx[x]+n,idx[x]});
        }
        for(auto u:S){
            for(auto v:divisor[u])if(S.contains(v)){
                E.push_back({idx[u],idx[v]});
                E.push_back({idx[u]+n,idx[v]+n});
                E.push_back({idx[u]+n,idx[v]});
            }
        }
        cout<<n-work(n<<1)<<endl;
    }
    return 0;
}

标签:return,idx,int,auto,定理,CF1630F,back,push,Dilworth
From: https://www.cnblogs.com/yoshinow2001/p/18383199

相关文章

  • T240827【定理3.3 Cauchy积分定理的 Goursat 证明】
    [T240819]Cauchy积分定理:设\(f(z)\)在\(z\)平面上的单连通区域\(D\)内解析,\(C\)为\(D\)内的任一条周线,则\[\int_Cf(z)~\mathrmdz=0\]证:【Goursat证明】Step1:若\(C\)为\(D\)内任一三角形\(\Delta\).假设\(|\int_{\Delta}f(z)~\mathrmdz|=M\),下证......
  • python实例演示贝叶斯定理在机器学习中的应用
    贝叶斯定理是一种概率论中的基本公式,用于计算在已知条件下事件发生的概率。它的通俗解释可以理解为:当你获得新信息时,如何更新对某个事件发生概率的判断。贝叶斯定理公式贝叶斯定理的数学表达式是:P(A∣B)=P(B∣A)⋅P(A)P(B)P(A|B)=\frac{P(B|A)\cdotP(A)}{P(B)}P(A∣B)=P......
  • 乘法逆元 + 扩展欧几里得定理/算法
    数学之乘法逆元Part1:逆元是什么一个东西的逆元,就是指在一种运算/操作下能够抵消这个东西所带来影响的东东举个例子4的加法逆元就是-4​ 2在普通乘法中的逆元就是\(2^{-1}\)而乘法逆元指的是在模意义下的乘法逆元设原式为​\(1*a\equiva\modp\)那么......
  • 中国剩余定理
    中国剩余定理,想必大家都没有接触过。那它到底是什么呢?让我们来一探究竟。一、关于中国剩余定理的历史中国剩余定理,亦被称作孙子定理,是数论领域中的一颗璀璨明珠。其历史可追溯至中国古代的南北朝时期,具体可见于经典著作《孙子算经》中。这一定理为求解其提供了一高效且精妙......
  • 中心极限定理
    中心极限定理(CentralLimitTheorem,CLT)是统计学中的一个重要定理,它描述了在某些条件下,大量独立随机变量的平均值的分布特性。简单来说,中心极限定理告诉我们:无论原始数据的分布是什么样的,只要样本量足够大,这些样本平均值的分布都会接近正态分布(钟形曲线)。详细解释1.背景和......
  • 信息学奥赛初赛天天练-72-NOIP2016普及组-基础题3-无向图、简单无向图、自环、平行边
    NOIP2016普及组基础题35以下不是存储设备的是()A光盘B磁盘C固态硬盘D鼠标6如果开始时计算机处于小写输入状态,现在有一只小老鼠反复按照CapsLock、字母键A、字母键S、字母键D、字母键F的顺序循环按键,即CapsLock、A、S、D、F、CapsLock、A、S、D、F......
  • Hall 定理
    Conventions我们约定\(G=(V,E)\)是一个标准的二分图,使用\(V_1,V_2\)来描述两侧的不同的集合,约定\(V_1\cupV_2=V\)且\(\left\lvertV_1\right\rvert<\left\lvertV_2\right\rvert\)。Theorem一个二分图存在完备匹配的充要条件是对于左部点大小为\(k\)的任意子集\(S\)......
  • 二项式定理
    二项式定理$\quad\quad\quad(x+y)^n=\sum_{k=0}^{n}{n\choosek}x^{n-k}y^k$证明\(\quad(x+y)^n=(x+y)*(x+y)*(x+y)*...\)我们考虑多项式乘法\((a+b)*(a+b)=a*a+a*b+b*a+b*b\)于是我们枚举每个因子相乘,可以发现\((x+y)^n\)每个括号里的\(x\)和\(y\)最多只能选......
  • 程序 · 杂谈 | DeepSeek发布最强开源数学定理证明模型
    DeepSeek-Prover-V1展示了大模型在数学定理证明领域的潜力,通过将数学问题转换为Lean编程语言,帮助数学家严格验证证明正确性。今天,DeepSeek开源Prover-V1.5版本,引入了类似AlphaGo的强化学习系统,模型通过自我迭代和Lean证明器监督,构建了一个“围棋”式的学习环境。最终,......
  • 题解:CF1630F Making It Bipartite
    题意图上有\(n\)个点,且具有点权,点权保证互不相同,若两个点点权有倍数关系,则两点之间有一边,问你最少删去多少个点能使图变为二分图。思路因为如果\(a\)是\(c\)的倍数且\(c\)是\(b\)的个数,所以\(a\)是\(c\)的倍数。由此可以看出,若\(a\)与\(b\)相连且\(b\)与......