1 条题解

  • 0
    @ 2026-4-27 23:38:35

    来一个瞎几把口胡的费用流做法

    首先每个点向目标点连边,显然是一个二分图完备匹配。

    然后显然直接跑 MCMF 是会寄掉的。

    不妨来想一想怎么让费用流模型帮我们“自动”计算费用。

    因为绕着一个环的那个绝对值的最小值相当于最短路,所以我们可以对于每个桌子,连一条边 (i,(i+1)modn,n)(i,(i+1)\bmod n,n)(最坏有 nn 个节点会经过这条边)

    然后在桌子与桌子之间连边。

    具体地

    对于 nmnm 个位置,每个位置连每张桌子上对应的位置

    每个桌子内部有 2m2m 条边。

    节点数量是 2nm+22nm+2,边数量是 n2m+2nmn^2m+2nm

    也许是可以跑过去的。(60026002 个点和 900600900600 条边)

    而且还有分层,边权也很有规律。。。

    需要注意的是此图存在负环,需要处理一下细节。

    好像数据有点儿水,直接跑就能过(

    以及不知道为什么要把前向星换成 vector 才能过。

    听说正解是把这个建图在连 [L,R][L,R] 的时候用线段树优化建图。(好像是说不这样的话不写 zkw 费用流过不去)

    #pragma GCC optimize(2)
    #pragma GCC optimize(3)
    #pragma GCC optimize("no-stack-protector")
    #pragma GCC optimize("-funroll-loops","-fdelete-null-pointer-checks")
    #include<cstdio>
    #include<vector>
    #include<queue>
    const int M=305,N=15;
    int n,m,s,t,tot,l[M][N],r[M][N],in[M][N],out[M][N];
    int d[6005];bool iq[6005],vis[6005];
    std::deque<int>q;int flow,ret;
    inline int min(const int&a,const int&b){return a>b?b:a;}
    inline int abs(const int&a){return a>0?a:-a;}
    struct Edge{
    	int v,w,flow,id;
    };std::vector<Edge>G[6005];
    inline void Add(const int&u,const int&v,const int&flow,const int&w){
    	G[u].push_back((Edge){v,w,flow,G[v].size()});
    	G[v].push_back((Edge){u,-w,0,G[u].size()-1});
    }
    inline bool BFS(){
    	for(int i=s;i<=t;++i)d[i]=0x7fffffff,vis[i]=false;d[s]=0;q.push_back(s);
    	while(!q.empty()){
    		const int u=q.front();int v;iq[u]=false;q.pop_front();
    		for(Edge&E:G[u])if(E.flow){
    			const int&w=d[u]+E.w;
    			if(w<d[v=E.v]){
    				d[v]=w;if(iq[v])continue;iq[v]=true;
    				if(!q.empty()&&d[v]<d[q.front()])q.push_front(v);else q.push_back(v);
    			}
    		}
    	}
    	return d[t]!=0x7fffffff;
    }
    inline int DFS(const int&u,const int&flow){
    	if(u==t)return flow;
    	int v,ret(flow);vis[u]=true;
    	for(Edge&E:G[u])if(d[v=E.v]==d[u]+E.w&&E.flow&&!vis[v]){
    		const int&F=DFS(v,min(ret,E.flow));if(!F)d[v]=-0x7fffffff;E.flow-=F;G[v][E.id].flow+=F;ret-=F;
    		if(!ret)return flow;
    	}
    	return flow-ret;
    }
    inline void Dinic(){
    	while(BFS())while(const int&F=DFS(s,n*m))ret+=F*d[t],flow+=F;
    	if(flow!=n*m)printf("no solution");else printf("%d",ret);
    }
    signed main(){
    	scanf("%d%d",&n,&m);
    	s=++tot;for(int i=1;i<=n;++i)for(int j=1;j<=m;++j)scanf("%d",l[i]+j),++l[i][j],in[i][j]=++tot;
    	for(int i=1;i<=n;++i)for(int j=1;j<=m;++j)scanf("%d",r[i]+j),++r[i][j],out[i][j]=++tot;t=++tot;
    	for(int i=1;i<=n;++i)for(int j=1;j<=m;++j){
    		Add(s,in[i][j],1,0);Add(out[i][j],t,1,0);Add(out[i][j],out[i][j%m+1],m,1);Add(out[i][j%m+1],out[i][j],m,1);
    		for(int k=l[i][j];k<=r[i][j];++k)Add(in[i][j],out[k][j],1,abs(i-k)<<1);
    	}
    	Dinic();
    }
    
    • 1

    信息

    ID
    10781
    时间
    5000ms
    内存
    512MiB
    难度
    10
    标签
    递交数
    1
    已通过
    1
    上传者