cf822C(贪心)

题目链接: http://codeforces.com/problemset/problem/822/C

 

题意: 有n条线段(n<=2e5) 每条线段有左端点li,右端点ri,价值cost(1 <= li <= ri <= 2e5, cost <= 1e9);

对于一个给定的x(x <= 2e5),寻找两个不相交的线段,使它们的长度和恰好为x,并且价值和最小;

 

思路: xjb贪心

这题目肯定是枚举一条线段再找剩下一条线段, 假设枚举右线段, 且其长为len1, 那么我们需要找这条线段左边的长度为 x - len1 的线段的 cost 最小值;直接暴力的话是n^2的复杂度, 肯定 tle. 可以给这些线段按照左右端点排下序, 那么我们可以从按左端点排序的数组中枚举右线段, 然后在按右端点排序的数组中找左线段;但是如果暴力找的话时间复杂度还是 n^2 . 我们可以维护一个 vis数组, vis[i] 为当前右线段的左边线段中长度为 i 的 cost 最小值, 那么 vis[x - len1] 即为当前左线段的 cost 最小值;

那么 cost1 + vis[x - len1] 的最小值即为答案啦;

 

代码:

 1 #include <iostream>
 2 #include <stdio.h>
 3 #include <string.h>
 4 #include <algorithm>
 5 #define ll long long
 6 using namespace std;
 7 
 8 const int MAXN = 2e5 + 10;
 9 const int inf = 0x7f7f7f7f;
10 ll vis[MAXN];
11 struct node{
12     int l, r;
13     ll w;
14 }gel1[MAXN], gel2[MAXN];
15 
16 bool cmp1(node a, node b){
17     return a.l < b.l;
18 }
19 
20 bool cmp2(node a, node b){
21     return a.r < b.r;
22 }
23 
24 int main(void){
25     int n, x;
26     ll ans = inf;
27     scanf("%d%d", &n, &x);
28     for(int i = 0; i < n; i++){
29         scanf("%d%d%lld", &gel1[i].l, &gel1[i].r, &gel1[i].w);
30         gel2[i] = gel1[i];
31     }
32     sort(gel1, gel1 + n, cmp1);
33     sort(gel2, gel2 + n, cmp2);
34     memset(vis, 0x7f, sizeof(vis));
35     int indx = 0;
36     for(int i = 0; i < n; i++){
37         ll gg = gel1[i].w;
38         while(indx < n && gel2[indx].r < gel1[i].l){
39             int cnt = gel2[indx].r - gel2[indx].l + 1;
40             if(vis[cnt] > gel2[indx].w) vis[cnt] = gel2[indx].w;
41             indx++;
42         }
43         int cc = x - (gel1[i].r - gel1[i].l + 1);
44         if(cc <= 0) continue;
45         gg += vis[cc];
46         if(ans > gg) ans = gg;
47     }
48     if(ans == inf) cout << -1 << endl;
49     else cout << ans << endl;
50     return 0;
51 }
View Code

 

posted @ 2017-07-04 14:06  geloutingyu  阅读(924)  评论(0编辑  收藏  举报