链接
题解
分析题目,如果一种方案中,某个点上覆盖了三条线段,那么肯定有一条线段即使去掉也能让剩下的线段覆盖整个区间,而且答案只可能变优而不可能变劣。
所以可以得出一个结论:一个点上面最多有两条线段
那么方案也就长这样:
先把线段按照右端点排序,然后开始 d p dp dp
d p [ i ] [ j ] dp[i][j] dp[i][j]表示强制选择第 i i i条线段,从 1 1 1到这条线段的右端都被覆盖了,而且从这个线段的左端点到 j − 1 j-1 j−1这个坐标都是被覆盖了两次的区间。满足以上条件的最小答案。
代码
#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
#define iinf 0x3f3f3f3f
#define linf (1ll<<60)
#define eps 1e-8
#define maxn 2020
#define cl(x) memset(x,0,sizeof(x))
#define rep(i,a,b) for(i=a;i<=b;i++)
#define drep(i,a,b) for(i=a;i>=b;i--)
#define em(x) emplace(x)
#define emb(x) emplace_back(x)
#define emf(x) emplace_front(x)
#define fi first
#define se second
#define de(x) cerr<<#x<<" = "<<x<<endl
using namespace std;
using namespace __gnu_pbds;
typedef long long ll;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;
ll read(ll x=0)
{
ll c, f(1);
for(c=getchar();!isdigit(c);c=getchar())if(c=='-')f=-f;
for(;isdigit(c);c=getchar())x=x*10+c-0x30;
return f*x;
}
struct Segment
{
ll l, r, w;
}seg[maxn];
ll dp[maxn][maxn];
int main()
{
ll T=read();
while(T--)
{
ll n=read(), m=read(), i, j, ans=linf;
rep(i,1,n)seg[i].l=read(), seg[i].r=read(), seg[i].w=read();
sort(seg+1,seg+n+1,[](Segment s1, Segment s2){return s1.r<s2.r;});
rep(i,0,n)rep(j,0,m+1)dp[i][j]=linf;
dp[0][1]=0;
rep(i,1,n)
{
rep(j,0,i-1)
{
ll t=linf;
if(seg[i].l<=seg[j].r)t=max(dp[j][seg[i].l],seg[j].w+seg[i].w);
else if(seg[i].l==seg[j].r+1)t=max(dp[j][seg[i].l],seg[i].w);
dp[i][seg[j].r+1]=min(dp[i][seg[j].r+1],t);
}
rep(j,seg[i].l+1,seg[i].r+1)dp[i][j]=min(dp[i][j],dp[i][j-1]);
if(seg[i].r==m)ans=min(ans,dp[i][m+1]);
}
if(ans==linf)printf("-1\n");
else printf("%lld\n",ans);
}
return 0;
}