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 }
我就是我,颜色不一样的烟火 --- geloutingyu