HDU 5596(更新,两种方法)

更新:

这是中文题目的链接:

http://bestcoder.hdu.edu.cn/contests/contest_chineseproblem.php?cid=659&pid=1001

 这道题还可以用优先队列来做,优先队列的特性可以很好的返回两个队列中b最小的值。

下面说过了,c[i] += c[i-1]是来获得前缀和。前面的节点没发功增加一次,就相当于b[i]-1,b[i]-c[i-1]的值,就是到达第i时间是,b[i]相对的减少量。我们设置两个队列,根据需要,将b[i]-c[i-1]的值分别放入不同的队列中,例如,当取到0组的数时,将该b[i]-c[i-1]放入0组队列,同时和1组队列的最小值比较,若1组较小,则去掉该元素,直到存在大的为止。

 1 #include<stdio.h>
 2 #include<queue>
 3 #include<string.h> 
 4 #define maxn 50005
 5 using namespace std;
 6 struct node1{
 7     int num;
 8     friend bool operator<(node1 a,node1 b){
 9         return b.num < a.num;
10     }
11 };
12 struct node2{
13     int group;
14     int b;
15 };
16 node2 a[maxn];
17 int c[maxn];
18 int main(){
19     int t;
20     scanf("%d",&t);
21     while(t--){
22         int n,m;
23         memset(c,0,sizeof(c));
24         priority_queue<node1>q[2];
25         scanf("%d%d",&n,&m);
26         for(int i = 1;i<=n;i++){
27             scanf("%d%d",&a[i].group,&a[i].b);
28         }
29         for(int i = 0;i<m;i++){
30             int time;
31             scanf("%d",&time);
32             c[time]++;
33         }
34         int ans = n;
35         node1 cur;
36         for(int i = 1;i<=n;i++){
37             c[i] += c[i-1];
38             if(a[i].group){
39                 cur.num = a[i].b-c[i-1];
40                 q[1].push(cur);
41                 while(!q[0].empty()&&q[0].top().num<cur.num){
42                     q[0].pop();
43                     ans--;
44                 }
45             }else{
46                 cur.num = a[i].b-c[i-1];
47                 q[0].push(cur);
48                 while(!q[1].empty()&&q[1].top().num<cur.num){
49                     q[1].pop();
50                     ans--;
51                 }
52             }
53         }
54         printf("%d\n",ans);
55     }
56     return 0;
57 }

 

——————————————————我是分割线————————————————————————————————

题目:

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

这道题可以很巧妙的用O(n)的时间复杂度做出来的。首先,当我们用一个数组c存储gt发功的时间时,以该时间为下标之前的b值都会加1,所以可以用c[i] += c[i-1],以获得当前节点之前,已累计法功多少次了,然后c[y]-c[x](y>x)就是以x为下标的gt,到y时间时,通过发功增加的量。

至于为什么要倒着处理呢,因为我们是要去掉小的元素,这样,我们只要从后往前,保存最大的元素,只要存在小于最大元素的,该元素就可以去掉了。

还有,max0、max1分别是1组的最大值和0组的最大值,以gt[i].b-c[i-1]-max0这个式子为例,我们这里假设x<y,max0 = gt[y].b-c[y-1],所以前面那个式子就可以化成gt[x].b-c[x-1]-gt[y].b-c[y-1] = gt[x].b-gt[y].b+c[y-1]-c[x-1],由我们前面的推导,c[y-1]-c[x-1]就是gt[x].b增加的量,这个值加上gt[x].b,如果减去gt[y].b小于0的话,说明该gt是要去掉的,同时要更新max1的值,以为此时处理的是0组的情况,保存最大的。

 1 #include<stdio.h>
 2 #include<string.h>
 3 #include<algorithm>
 4 #define maxn 50005
 5 #define inf 0x3f3f3f3f
 6 using namespace std;
 7 struct node{
 8     int group;
 9     int b;
10 };
11 node gt[maxn];
12 int c[maxn];
13 int main(){
14     int t;
15     scanf("%d",&t);
16     while(t--){
17         int n,m;
18         memset(c,0,sizeof(c));
19         scanf("%d%d",&n,&m);
20         for(int i = 1;i<=n;i++){
21             scanf("%d%d",&gt[i].group,&gt[i].b);
22         }
23         for(int i = 1;i<=m;i++){
24             int temp;
25             scanf("%d",&temp);
26             c[temp]++;
27         }
28         for(int i = 1;i<=n;i++){
29             c[i] += c[i-1];
30         } 
31         int ans = n;
32         int max0 = -inf,max1 = -inf;
33         for(int i = n;i>0;i--){
34             if(gt[i].group){
35                 if(gt[i].b-c[i-1]-max0<0)
36                     ans--;
37                 max1 = max(max1,gt[i].b-c[i-1]);
38             }else{
39                 if(gt[i].b-c[i-1]-max1<0)
40                     ans--;
41                 max0 = max(max0,gt[i].b-c[i-1]);
42             }
43         }
44         printf("%d\n",ans);
45     } 
46     return 0;
47 }

 

---恢复内容结束---

题目:

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

这道题可以很巧妙的用O(n)的时间复杂度做出来的。首先,当我们用一个数组c存储gt发功的时间时,以该时间为下标之前的b值都会加1,所以可以用c[i] += c[i-1],以获得当前节点之前,已累计法功多少次了,然后c[y]-c[x](y>x)就是以x为下标的gt,到y时间时,通过发功增加的量。

至于为什么要倒着处理呢,因为我们是要去掉小的元素,这样,我们只要从后往前,保存最大的元素,只要存在小于最大元素的,该元素就可以去掉了。

还有,max0、max1分别是1组的最大值和0组的最大值,以gt[i].b-c[i-1]-max0这个式子为例,我们这里假设x<y,max0 = gt[y].b-c[y-1],所以前面那个式子就可以化成gt[x].b-c[x-1]-gt[y].b-c[y-1] = gt[x].b-gt[y].b+c[y-1]-c[x-1],由我们前面的推导,c[y-1]-c[x-1]就是gt[x].b增加的量,这个值加上gt[x].b,如果减去gt[y].b小于0的话,说明该gt是要去掉的,同时要更新max1的值,以为此时处理的是0组的情况,保存最大的。

 1 #include<stdio.h>
 2 #include<string.h>
 3 #include<algorithm>
 4 #define maxn 50005
 5 #define inf 0x3f3f3f3f
 6 using namespace std;
 7 struct node{
 8     int group;
 9     int b;
10 };
11 node gt[maxn];
12 int c[maxn];
13 int main(){
14     int t;
15     scanf("%d",&t);
16     while(t--){
17         int n,m;
18         memset(c,0,sizeof(c));
19         scanf("%d%d",&n,&m);
20         for(int i = 1;i<=n;i++){
21             scanf("%d%d",&gt[i].group,&gt[i].b);
22         }
23         for(int i = 1;i<=m;i++){
24             int temp;
25             scanf("%d",&temp);
26             c[temp]++;
27         }
28         for(int i = 1;i<=n;i++){
29             c[i] += c[i-1];
30         } 
31         int ans = n;
32         int max0 = -inf,max1 = -inf;
33         for(int i = n;i>0;i--){
34             if(gt[i].group){
35                 if(gt[i].b-c[i-1]-max0<0)
36                     ans--;
37                 max1 = max(max1,gt[i].b-c[i-1]);
38             }else{
39                 if(gt[i].b-c[i-1]-max1<0)
40                     ans--;
41                 max0 = max(max0,gt[i].b-c[i-1]);
42             }
43         }
44         printf("%d\n",ans);
45     } 
46     return 0;
47 }

 

你可能感兴趣的:(HDU 5596(更新,两种方法))