这题比较考验思维。。看了咖啡鸡的转移就秒懂了 。。
首先显然每个点最多被2个区间覆盖。。
然后在加入区间的时候就必须保证每个点最多被覆盖2次,不然不是最优。。
其实这个性质给DP带来了不少便利。。少考虑了很多情况。。。在加入区间的同时需要知道最后覆盖了2个点的坐标。。
所以可以这么设计。。设d[i][j]为取第i个区间且j-r[i]只被覆盖一次的最小值。。
然后d[i][j]并不需要被全扫出来。。只要通过前i-1个区间转移到i的一些状态就行。。而这些状态已经涵盖了所有的情况。。
转移见代码更容易理解。。
/**
* ┏┓ ┏┓
* ┏┛┗━━━━━━━┛┗━━━┓
* ┃ ┃
* ┃ ━ ┃
* ┃ > < ┃
* ┃ ┃
* ┃... ⌒ ... ┃
* ┃ ┃
* ┗━┓ ┏━┛
* ┃ ┃ Code is far away from bug with the animal protecting
* ┃ ┃ 神兽保佑,代码无bug
* ┃ ┃
* ┃ ┃
* ┃ ┃
* ┃ ┃
* ┃ ┗━━━┓
* ┃ ┣┓
* ┃ ┏┛
* ┗┓┓┏━━━━━━━━┳┓┏┛
* ┃┫┫ ┃┫┫
* ┗┻┛ ┗┻┛
*/
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<queue>
#include<cmath>
#include<map>
#include<stack>
#include<set>
#define inc(i,l,r) for(int i=l;i<=r;i++)
#define dec(i,l,r) for(int i=l;i>=r;i--)
#define link(x) for(edge *j=h[x];j;j=j->next)
#define mem(a) memset(a,0,sizeof(a))
#define ll long long
#define eps 1e-8
#define succ(x) (1LL<<x)
#define lowbit(x) (x&(-x))
#define sqr(x) ((x)*(x))
#define mid (x+y>>1)
#define NM 2005
#define nm 400000
#define N 1000005
#define M(x,y) x=max(x,y)
const double pi=acos(-1);
const int inf=1e9+7;
using namespace std;
ll read(){
ll x=0,f=1;char ch=getchar();
while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
return f*x;
}
struct tmp{
int l,r,w;
bool operator<(const tmp&o){return r<o.r;}
}a[NM];
int n,m,d[NM][NM],f[NM][NM],ans;
int main(){
int _=read();while(_--){
n=read();m=read();ans=inf;
inc(i,1,n)a[i].l=read(),a[i].r=read(),a[i].w=read();
sort(a+1,a+1+n);
inc(i,1,n){
inc(j,0,m)d[i][j]=f[i][j]=inf;
if(a[i].l==1)inc(j,1,a[i].r)d[i][j]=a[i].w;
inc(j,1,m)f[i][j]=min(d[i][j],f[i][j-1]);
}
// inc(i,1,n)printf("%d %d %d\n",a[i].l,a[i].r,a[i].w);
// inc(i,1,n){inc(j,1,m)printf("%d ",d[i][j]);putchar('\n');}
inc(i,1,n){
inc(j,1,i-1)if(a[i].l==a[j].r+1)d[i][a[i].l]=min(d[i][a[i].l],max(f[j][m],a[i].w));
else if(a[i].l<=a[j].r)d[i][a[j].r+1]=min(d[i][a[j].r+1],max(f[j][a[i].l],a[i].w+a[j].w));
inc(j,1,m)f[i][j]=min(f[i][j-1],d[i][j]);
}
// inc(i,1,n){inc(j,1,m)printf("%d ",d[i][j]);putchar('\n');}
dec(i,n,1)if(a[i].r==m)ans=min(ans,f[i][m]);else break;
if(ans<inf)printf("%d\n",ans);else printf("-1\n");
}
return 0;
}
Interval Revisited
链接:https://www.nowcoder.com/acm/contest/142/B
来源:牛客网
时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 131072K,其他语言262144K
64bit IO Format: %lld
题目描述
Chiaki has a long interval [1,m] and n small intervals [l1, r1], [l2,r2], ..., [ln, rn]. Each small interval [li,ri] is associated with a weight wi.
Chiaki would to select some small intervals such that:
- each integer position x ∈ [1, m] is covered by at least one small interval.
- let sx be the sum of the weights of all the small intervals covering position x, the maximum value of sx should be minimum.
Chiaki would like to know the minimum value of maximum sx.
输入描述:
There are multiple test cases. The first line of input contains an integer T, indicating the number of test cases. For each test case: The first line contains two integers n and m (1 ≤ n, m ≤ 2000) -- the number of small intervals and the length of the long interval. Each of the next n lines contains three integers li, ri and wi (1 ≤ li ≤ ri ≤ m, 1 ≤ wi ≤ 1000). It is guaranteed that the sum of all n does not exceed 20000.
输出描述:
For each test case, output an integer denoting the answer, or -1 if Chiaki cannot select such intervals.
示例1
输入
复制
2 2 4 1 2 2 3 4 5 1 4 1 3 1
输出
复制
5 -1