哎失望地开始口糊题解了呀,bzoj2879 TLE调不出来,于是难过地开始整理AC的题了(ಥ﹏ಥ)...
这题很有想法的!
题意:有n个区间,每个区间有一个权值wi,从中取一些区间,使得任意整数点的被包含次数小于等于k,并且这些区间的权值和最大。
题解:这题和志愿者招募蜜汁相似啊ww~~
对于每个点列出式子。
设xi表示第i个区间有没有包含该点,xi=0 or 1
再引入一个余量ri
这样式子可以写成:
0+r0=k
x1+x3+x6+r1=k
x2+x5+x6+r2=k
......
0+rn+1=k
相邻两点相减,x2+x5+r2-x1-x3-r1=0
看见右端为0,可以想到一个点的入流=出流。
而相邻两个点相减多出来的一定是新产生的或者是新消失的。
那么就可以把问题转化成费用流啦!
区间的两个端点连边,流量为1,费用为-wi(否则不会去流)
相邻端点之间连边,流量为k,费用为0
建立源点和汇点与第一个和最后一个点连边。
跑费用流即可。
这题或许有点难理解(真的w
边数初始化1这个东西永远不能忘!!
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <queue>
#include <map>
#define N 1010
using namespace std;
int Q,n,k,cnt,tot,S,T,ans,mark[N],dis[N],head[N],cur[N],c[N],a[N],b[N],w[N];
map<int,int> id;
const int inf=1e9;
struct edge{
int from,to,next,v,c;
}e[N];
inline int read(){
int x=0,f=1;char ch=getchar();
while (ch<'0' || ch>'9'){if (ch=='-') f=-1;ch=getchar();}
while (ch>='0' && ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
inline void add_edge(int x,int y,int v,int c){
e[++cnt]=(edge){x,y,head[x],v,c};head[x]=cnt;
e[++cnt]=(edge){y,x,head[y],0,-c};head[y]=cnt;
}
inline bool spfa(){
memset(mark,0,sizeof(mark));
for(int i=0;i<=T;i++) dis[i]=inf;
queue<int>q;
dis[S]=0;q.push(S);mark[S]=1;
while(!q.empty()){
int now=q.front();q.pop();
for(int i=head[now];i!=-1;i=e[i].next){
int v1=e[i].to;
if(e[i].v && dis[v1]>dis[now]+e[i].c){
dis[v1]=dis[now]+e[i].c;
cur[v1]=i;
if(!mark[v1]){q.push(v1);mark[v1]=1;}
}
}
mark[now]=0;
}
return dis[T]!=inf;
}
inline void mcf(){
ans=0;
while(spfa()){
int flow=inf;
for(int i=cur[T];i;i=cur[e[i].from]) flow=min(flow,e[i].v);
ans+=flow*dis[T];
for(int i=cur[T];i;i=cur[e[i].from]){e[i].v-=flow;e[i ^ 1].v+=flow;}
}
}
int main()
{
Q=read();
while(Q--){
memset(head,-1,sizeof(head));
memset(cur,0,sizeof(cur));
memset(c,0,sizeof(c));
n=read();k=read();
for(int i=1;i<=n;i++){
a[i]=read();b[i]=read();w[i]=read();
c[i+i-1]=a[i];c[i+i]=b[i];
}
sort(c+1,c+n+n+1);
tot=0;cnt=1;
for(int i=1;i<=n+n;i++) if(i==1 || c[i] != c[i-1]) id[c[i]]=++tot;
S=0;T=tot+1;
for(int i=1;i<tot;i++) add_edge(i,i+1,k,0);
add_edge(S,1,k,0);add_edge(tot,T,k,0);
for(int i=1;i<=n;i++) add_edge(id[a[i]],id[b[i]],1,-w[i]);
mcf();
printf("%d\n",-ans);
}
return 0;
}