题目大意是给若干线段及其费用,每个线段权值即为其长度。要求找出两个不重合线段,令其权值和等于x且费用最少。
解法:
先分析一下题目,要处理不重合的问题,有重合的线段不能组合,其次这是一个选二问题,当枚举其中一条线段时,另一条合法线段的必要条件“权值”可以直接得出。
对于第一个问题,想到先对线段根据l进行排序,这样每次枚举一个线段的时候,如果在它的l之后有一个合法线段,我们只要标记一下x-LenNow,待枚举到那个合法线段的时候自然就判断出来了。如果在它之前有一个合法线段符合条件,根据刚刚的做法我们自然可以处理。现在问题就是,万一它不合法,它重合呢?解决方法就是延迟标记它。对于线段们,我们已经对l排序,那么一旦枚举到一条线段的l大于等于之前待标记的某线段的r,那它及之后的线段都不会与它重合,而之前的线段(标记线段之后的线段)一定与它重合。所以我们维护一个优先队列,以待标记的r进行排序,每次枚举前,根据枚举到线段的l将部分待标记物执行标记即可。
撤了那么多,看看代码吧。
#include <iostream>
#include <algorithm>
#include <cmath>
#include <vector>
#include <string>
#include <queue>
#define LL long long int
using namespace std;
struct node
{
LL r,len,c;
friend bool operator < (node a,node b)
{
return a.r>b.r; }
};//用于延迟标记
struct cd
{
LL l,r,c;
};
LL mi[];
const LL inf=;
vector<cd> v;
bool cmp(cd a,cd b)
{
if(a.l==b.l)
return a.r<b.r;
return a.l<b.l;
}
int main()
{
LL n,x;
while(cin>>n>>x)
{
LL a,b,c;
LL ans=inf;
v.clear();
fill(mi,mi+,inf);
priority_queue<node> upt;
for(LL i=;i<n;i++)
{
cin>>a>>b>>c;
v.push_back((cd){a,b,c});
}
sort(v.begin(),v.end(),cmp);
for(int i=;i<v.size();i++)
{
while(!upt.empty())
{
node check=upt.top();
if(v[i].l<=check.r) break;
upt.pop();
if(mi[check.len]>check.c)
mi[check.len]=check.c;
}
cd now=v[i];
LL len=now.r-now.l+;
LL f=x-len;
upt.push((node){now.r,len,now.c});
if(f<=) continue;
if(now.c+mi[f]<ans) ans=now.c+mi[f];
}
if(ans!=inf)
cout<<ans<<endl;
else
cout<<-<<endl;
}
return ;
}