题解:
首先要处理出每个时间点会选择哪一个线段。
对于这个问题,可以用multiset去维护信息。
当时间线开始的时候,往mutiset里面插入这个信息,当时间线结束的时候,删除这个信息。
每次只要取出最大位就好了。
然后,就是状态转移,注意的就是只有转移进来过的状态才能转移出去。
代码:
/* code by: zstu wxk time: 2019/02/03 */ #include<bits/stdc++.h> using namespace std; #define Fopen freopen("_in.txt","r",stdin); freopen("_out.txt","w",stdout); #define LL long long #define ULL unsigned LL #define fi first #define se second #define pb push_back #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 #define lch(x) tr[x].son[0] #define rch(x) tr[x].son[1] #define max3(a,b,c) max(a,max(b,c)) #define min3(a,b,c) min(a,min(b,c)) typedef pair<int,int> pll; const int inf = 0x3f3f3f3f; const int _inf = 0xc0c0c0c0; const LL INF = 0x3f3f3f3f3f3f3f3f; const LL _INF = 0xc0c0c0c0c0c0c0c0; const LL mod = (int)1e9+7; const int N = 1e5 + 100; int n, m, k; struct Node{ int d, w; bool operator < (const Node & x) const{ if(w == x.w) return d > x.d; return w > x.w; } }; vector<Node> in[N], out[N]; LL dp[N][210]; multiset<Node> st; void Ac(){ for(int i = 1; i <= k; ++i){ int s, t, d, w; scanf("%d%d%d%d", &s, &t, &d, &w); in[s].pb({d,w}); out[t].pb({d,w}); } memset(dp, INF, sizeof dp); dp[1][0] = 0; for(int i = 1; i <= n; ++i){ for(Node & x : in[i]){ st.insert(x); for(int j = 0; j <= m; ++j){ if(dp[i][j] == INF) continue; dp[i+1][j+1] = min(dp[i+1][j+1], dp[i][j]); if(st.empty()) dp[i+1][j] = min(dp[i+1][j], dp[i][j]); else { Node x = *st.begin(); dp[x.d+1][j] = min(dp[x.d+1][j], dp[i][j]+x.w); } } for(Node &x : out[i]) st.erase(st.lower_bound(x)); } LL ans = INF; for(int j = 0; j <= m; ++j) ans = min(ans, dp[n+1][j]); printf("%I64d\n", ans); } int main(){ while(~scanf("%d%d%d", &n, &m, &k)){ Ac(); } return 0; }View Code