【题解】P3358 最长k可重区间集问题

最长k可重区间集问题

题目描述

给定实直线 \(\text{L}\)\(n\) 个开区间组成的集合 \(\mathbf{I}\),和一个正整数 \(k\),试设计一个算法,从开区间集合 \(\mathbf{I}\) 中选取出开区间集合 \(\mathbf{S}\subseteq\mathbf{I}\),使得在实直线 \(\text{L}\) 上的任意一点 \(x\)\(\text{S}\) 中包含 \(x\) 的开区间个数不超过 \(k\),且 \(\sum_{z\in\text{S}}\lvert z\rvert\) 达到最大(\(\lvert z\rvert\) 表示开区间 \(z\) 的长度)。

这样的集合 \(\mathbf{S}\) 称为开区间集合 \(\mathbf{I}\) 的最长 \(k\) 可重区间集。\(\sum_{z\in\text{S}}\lvert z\rvert\) 称为最长 \(k\) 可重区间集的长度。

对于给定的开区间集合 \(\mathbf{I}\) 和正整数 \(k\),计算开区间集合 \(\mathbf{I}\) 的最长 \(k\) 可重区间集的长度。

输入格式

输入的第一行有 \(2\) 个正整数 \(n\)\(k\),分别表示开区间的个数和开区间的可重叠数。接下来的 \(n\) 行,每行有 \(2\) 个整数,表示开区间的左右端点坐标 \(l,r\),数据保证 \(l<r\)

输出格式

输出最长 \(k\) 可重区间集的长度。

样例 #1

样例输入 #1

4 2
1 7
6 8
7 10
9 13

样例输出 #1

15

提示

对于 \(100\%\) 的数据,\(1\le n\le 500\)\(1\le k\le 3\)

题解

考虑某点重叠不超过 $ k $ 和网络流中的流量限制非常相似,于是可以类似建图:

  • 离散化
  • 每个区间左端点向右端点连一条价值为 \(len\) ,流量为\(1\)的边
  • 离散化后的点每点向其右边的点连一条流量为\(k\),价值为\(0\)的边.
  • 从原点释放\(k\)的流量

直接跑费用流即可。

此题启发我们网络流的题目思考每一条流的意义是什么,同时要注意找增广路的过程实际和反悔过程同时进行

点击查看代码
#include<bits/stdc++.h>
using namespace std;
inline int rd(){
	int f=1,j=0;
	char w=getchar();
	while(!isdigit(w)){
		if(w=='-')f=-1;
		w=getchar();
	}
	while(isdigit(w)){
		j=j*10+w-'0';
		w=getchar();
	}
	return f*j;
}

const int N=5001,M=200001;
int head[N],to[M],fro[M],val[M],flo[M],tail=1;
int n,K,fl[N],va[N];
int s,t,cnt,ans;
int dig[N],tot,L[N],R[N],par[N],fr[N],fa[N];
bool inque[N];

inline void addlin(int x,int y,int a,int b){
	to[++tail]=y;
	fro[tail]=head[x];
	head[x]=tail;
	flo[tail]=a,val[tail]=b;
	to[++tail]=x;
	fro[tail]=head[y];
	head[y]=tail;
	flo[tail]=0,val[tail]=-b;
	return ;
}
bool spfa(int last){
	deque<int>p;
	for(int i=1;i<=cnt;i++)fl[i]=inque[i]=fr[i]=fa[i]=0,va[i]=-1;
	fl[s]=last,va[s]=0;
	p.push_back(s);
	while(!p.empty()){
		int u=p.front();p.pop_front();
		inque[u]=false;
		for(int k=head[u];k;k=fro[k]){
			int x=to[k];
			if(!flo[k]||va[x]>=va[u]+val[k])continue;
			va[x]=va[u]+val[k];
			fl[x]=min(fl[u],flo[k]);
			fr[x]=k,fa[x]=u;
			if(!inque[x])inque[x]=true,p.push_back(x); 
		}
	}
	return fl[t]!=0;
}

signed main(){
	n=rd(),K=rd();
	s=++cnt,t=++cnt;
	for(int i=1;i<=n;i++)L[i]=dig[++tot]=rd(),R[i]=dig[++tot]=rd();
	sort(dig+1,dig+1+tot);
	tot=unique(dig+1,dig+1+tot)-dig-1;
	for(int i=0;i<=tot;i++)par[i]=++cnt;
	for(int i=1;i<=tot;i++)addlin(par[i-1],par[i],K,0);
	addlin(s,par[0],K,0),addlin(par[tot],t,K,0);
	for(int i=1;i<=n;i++){
		int len=R[i]-L[i];
		L[i]=lower_bound(dig+1,dig+1+tot,L[i])-dig;
		R[i]=lower_bound(dig+1,dig+1+tot,R[i])-dig;
		addlin(par[L[i]],par[R[i]],1,len);
	}
	while(K&&spfa(K)){
		K-=fl[t];
		ans+=fl[t]*va[t];
		for(int u=t;u!=s;u=fa[u]){
			flo[fr[u]]-=fl[t];
			flo[fr[u]^1]+=fl[t];
		}
	}
	printf("%d",ans);
	return 0;
}
posted @ 2022-12-12 11:28  flywatre  阅读(52)  评论(0)    收藏  举报