HDU 4509 湫湫系列故事——减肥记II(线段树-区间覆盖 或者 暴力技巧)

http://acm.hdu.edu.cn/showproblem.php?pid=4509

题目大意:

  中文意义,应该能懂。

解题思路:

  因为题目给的时间是一天24小时,而且还有分钟。为了解题方便,我们将小时换成分钟,那么一天24小时,总共有1440分钟。顾我就可以把一天里的任意HH:MM时间换成分钟。就这样一天的时间就变成[0,1440]区间了。

  因为所给的活动最多是5*10^5,如果把活动的时间在线段[0,1440]都修改,那么时间的复杂度最坏是O(5*10^5*1440)。

  (1)方法一:线段树-区间覆盖。

  线段树参考的是《算法入门经典训练指南》刘汝佳 P199

线段树其中一个特性,区间修改。我们把[0,1440]看成一个区间,我们只需要把活动时间的在线段树中标记就行。因为线段树是区间,每次标记都是区间。所以时间复杂度最坏O(5*10^5*log(1440)),我们只要查询[0,1440]整个区间,统计被覆盖的时间ans,用1440-ans=最后的答案。

  查询时间的复杂度最坏是整棵树的节点O(2*1440)。

  所以总时间复杂度最坏是O(5*10^5*log(1440))+ O(2*1440)。

  注意:线段树的真正区间[1,1440],叶子节点表示是1秒的时间。

  (2)方法二:暴力技巧

  这个方法是借鉴别人的。

为了好理解这个方法,我们先举个简单的例子。

我们假设区间是[0,8]。

输入的数据是:

3

1 4

3 5

6 7

求未覆盖的线段和的长度。答案是3。

  具体方法是。当输入1 4时,将1出+1,表示1后面的区间被覆盖了1次,在4出-1,表示4后面的区间取消覆盖1次。 这样就表示了1 4区间被覆盖了。3 5和6 7也是同理。

  怎么求那些区间没有覆盖了,我是从0开始到结束,看每个小区间是否被覆盖。用一个count记录,若count为零时,表示此节点没有被覆盖。

  区间修改的时间复杂度是O(5*10^5*1),区间查询是整个区间时间复杂度是O(1440)

顾总时间复杂度是O(5*10^5*1)+O(1440)

AC代码:

线段树

 1 #include<cstdio>
 2 #include<cstring>
 3
 4 #define MAXN 1441//时间最多是1440
 5
 6 bool stree[MAXN << 2];//线段树
 7
 8 int L, R;//要覆盖的区间为[L,R]
 9 void updata(int o, int lc, int rc){//区间覆盖
10     if(stree[o]) return ;//此区间被覆盖了
11     if(L <= lc && rc <= R){//区间[lc,rc]在被覆盖的范围
12         stree[o] = true;
13         return ;
14     }
15     int mid = (lc + rc) >> 1;
16     if(L <= mid) updata(o * 2 + 1, lc, mid);
17     if(mid < R) updata(o * 2 + 2, mid + 1, rc);
18 }
19
20 int ans;//统计被覆盖的时间和
21 void query(int o, int lc, int rc){
22     if(stree[o]){
23         ans += rc - lc + 1;
24         return ;
25     }
26
27     if(lc == rc) return ;//访问到叶子节点了
28
29     int mid = (lc + rc) >> 1;
30     query(o * 2 + 1, lc, mid);
31     query(o * 2 + 2, mid + 1, rc);
32 }
33
34 int main(){
35     int n, hh[2], mm[2];
36     while(~scanf("%d", &n)){
37
38         memset(stree, 0, sizeof(stree));
39         while(n--){
40             scanf("%d:%d %d:%d", &hh[0], &mm[0], &hh[1], &mm[1]);
41             mm[0] += hh[0] * 60 + 1;
42             mm[1] += hh[1] * 60;
43             L = mm[0]; R = mm[1];
44             updata(0, 1, 1440);//区间修改
45         }
46         ans = 0;
47         query(0, 1, 1440);//区间访问
48         printf("%d\n", 1440 - ans);
49     }
50     return 0;
51 }

暴力技巧:

 1 #include<cstdio>
 2 #include<cstring>
 3
 4 #define MAXN 1441
 5
 6 int time[MAXN];
 7
 8 int main(){
 9     int n, hh[2], mm[2];
10     while(~scanf("%d", &n)){
11
12         memset(time, 0, sizeof(time));
13         while(n--){
14             scanf("%d:%d %d:%d", &hh[0], &mm[0], &hh[1], &mm[1]);
15             mm[0] += hh[0] * 60;
16             mm[1] += hh[1] * 60;
17
18             ++time[mm[0]]; --time[mm[1]];
19         }
20
21         int ans = 0, count = 0;
22         for(int i = 0; i < 1440; ++i){
23             count += time[i];
24             if(count == 0) ++ans;
25         }
26         printf("%d\n", ans);
27     }
28     return 0;
29 }
时间: 2024-10-13 00:32:39

HDU 4509 湫湫系列故事——减肥记II(线段树-区间覆盖 或者 暴力技巧)的相关文章

HDU4509-湫湫系列故事——减肥记II(线段树)

湫湫系列故事--减肥记II Time Limit: 5000/2000 MS (Java/Others)    Memory Limit: 65535/32768 K (Java/Others) Total Submission(s): 2395    Accepted Submission(s): 1018 Problem Description 虽然制定了减肥食谱,但是湫湫显然克制不住吃货的本能,根本没有按照食谱行动! 于是,结果显而易见- 但是没有什么能难倒高智商美女湫湫的,她决定另寻对策

hdu4509 湫湫系列故事——减肥记II (离散化思想)

Problem Description http://acm.hdu.edu.cn/showproblem.php?pid=4509 虽然制定了减肥食谱,但是湫湫显然克制不住吃货的本能,根本没有按照食谱行动! 于是,结果显而易见- 但是没有什么能难倒高智商美女湫湫的,她决定另寻对策--吃没关系,咱吃进去再运动运动消耗掉不就好了? 湫湫在内心咆哮:"我真是天才啊~\(≧▽≦)/~" 可是,大家要知道,过年回家多忙啊--帮忙家里做大扫除,看电影,看小说,高中同学聚餐,初中同学聚餐,小学同学

HDU ACM 4509 湫湫系列故事——减肥记II

分析:这题貌似还可以用线段树做,这里使用memset函数很方便的实现. #include<iostream> using namespace std; int main() { int a[1445],i,n,hh,mm; int s,t,count; while(scanf("%d",&n)==1) { memset(a,-1,sizeof(a)); for(i=0;i<n;i++) { scanf("%d:%d",&hh,&am

HDOJ 4509 湫湫系列故事——减肥记II(2013腾讯编程马拉松) 并查集合并区间

发现这种合并区间的题目还可以这么玩 给你n段时间 然后问没被占用的时间是多少 题目所给的区间是右开的导致我wa 好多人5e5*1440的暴力跑出来的时间居然只是我的两倍 不懂.... 所以并查集并没有跑的很快  奇怪.... 1 #include <stdio.h> 2 #include <iostream> 3 #include <algorithm> 4 #include <string.h> 5 #include <math.h> 6 #i

HDU 4508 湫湫系列故事——减肥记I (2013腾讯编程马拉松初赛第一场)

http://acm.hdu.edu.cn/showproblem.php?pid=4508 题目大意: 给定一些数据. 每组数据以一个整数n开始,表示每天的食物清单有n种食物. 接下来n行,每行两个整数a和b,其中a表示这种食物可以带给湫湫的幸福值(数值越大,越幸福),b表示湫湫吃这种食物会吸收的卡路里量. 最后是一个整数m,表示湫湫一天吸收的卡路里不能超过m. 思路: 完全背包. 一开始以为是01背包. 敲了01后样例2不对啊!!! 然后改成完全就过了..就改循环体就好了.. #includ

HDU 4508.湫湫系列故事——减肥记I【背包】【算法的优化】【8月13】

湫湫系列故事--减肥记I Problem Description 对于吃货来说,过年最幸福的事就是吃了,没有之一! 但是对于女生来说,卡路里(热量)是天敌啊! 资深美女湫湫深谙"胖来如山倒,胖去如抽丝"的道理,所以她希望你能帮忙制定一个食谱,能使她吃得开心的同时,不会制造太多的天敌. 当然,为了方便你制作食谱,湫湫给了你每日食物清单,上面描述了当天她想吃的每种食物能带给她的幸福程度,以及会增加的卡路里量. Input 输入包含多组测试用例. 每组数据以一个整数n开始,表示每天的食物清单

湫湫系列故事——减肥记I(杭电4508)(完全背包)

湫湫系列故事--减肥记I Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 65535/32768 K (Java/Others) Total Submission(s): 2612    Accepted Submission(s): 1345 Problem Description 对于吃货来说,过年最幸福的事就是吃了,没有之一! 但是对于女生来说,卡路里(热量)是天敌啊! 资深美女湫湫深谙"胖来如山倒,胖去如抽丝"的道

HDU4508 湫湫系列故事——减肥记I

这题一开始看还以为是0,1背包问题,不过老师说过了完全背包就按照这个思路做.(虽然偷偷去百度了一下到底是不是,有点怀疑老师是不是记错了的说); 顺便记下对一维数组方程的理解; for(int i =1;i<=n;i++)有n次就可以啦;//闭区间 for(int j=b[i];j<=m;j++)//每进行一次循环,第i件物品数加1或者0; dp[j]=max(dp[j],dp[j-b[i]]+a[i]);//如果是最优解的话,先后顺序无所谓是不是; 下面给出代码.嘻嘻. //这个在背包九讲里面

HDU4508 湫湫系列故事——减肥记I 【完全背包】

湫湫系列故事--减肥记I Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 65535/32768 K (Java/Others) Total Submission(s): 2458    Accepted Submission(s): 1254 Problem Description 对于吃货来说,过年最幸福的事就是吃了,没有之一! 但是对于女生来说,卡路里(热量)是天敌啊! 资深美女湫湫深谙"胖来如山倒,胖去如抽丝"的道