题目链接:
Problem - 822C - Codeforces
题意:
有n种行程选择,第i种是开始日期是l,结束日期是r,包括第l天和第r天(共r-l+1天),花费为w,从其中选择两个完全不冲突的行程(即这两个行程完全不相交),使得两个行程相加刚好为x天,同时花费最少。若存在输出最小花费,否则输出-1。
思路:
题目要求选择两个区间,不相交且相加等于x。这里我们把所有端点从小到大排序, 如果碰到的这个端点是右端点,说明右端点对应的这个区间我已经走完了,用一个cost数组记录对应此区间长的最小花费(不断更新),如果这个点是左端点, 那么它可以加上前面已经走过的的区间中的差等于 x - 当前区间长 中花费最小的值(cost[x - 当前区间长])来跟当前的ans进行比较取最小。
trick:两个区间不相交要求端点也不能重合,故排序的时候,让左端点排在前面, 这样在遍历x这个点时,所有以x为右端点的区间都还没有更新cost。
样例
代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int inf=2e9+10;
const int N=2e5+10;
int n,x;
int cost[N];
typedef struct Segment{
int pos1;//主键
int pos2;//区间的另一个点
int co;//花费
int type;//标记主键是左端点(type=-1)还是右端点(type=1)
}Segment;
Segment seg[N*2];
bool cmp(Segment x,Segment y){
if(x.pos1==y.pos1)
return x.type<y.type;
return x.pos1<y.pos1;
}
int main(){
scanf("%d%d",&n,&x);
int l,r,w;
int cnt=0;
for(int i=1;i<=n;i++){
scanf("%d %d %d",&l,&r,&w);
seg[++cnt]={l,r,w,-1};
seg[++cnt]={r,l,w,1};
}
sort(seg+1,seg+cnt+1,cmp);
int ans=inf,len;
for(int i=1;i<cnt;i++){
if(seg[i].type==-1){//左端点
len=seg[i].pos2-seg[i].pos1+1;
if(x<len||cost[x-len]==0)
continue;
else
ans=min(ans,seg[i].co+cost[x-len]);
}
else{
len=seg[i].pos1-seg[i].pos2+1;
if(cost[len]==0)
cost[len]=seg[i].co;
else
cost[len]=min(cost[len],seg[i].co);
}
}
if(ans==inf)
printf("-1");
else
printf("%d",ans);
}