zoukankan      html  css  js  c++  java
  • 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
    ",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
    ",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
    ",ans);
    45     } 
    46     return 0;
    47 }
  • 相关阅读:
    在Mac系统下使用自己安装的PHP
    在一个文件里追加内容和换行
    Linux系统下如何去掉文件的@属性
    composer的安装和使用
    Git SSH Key 生成步骤
    自定义mysql函数时报错,[Err] 1418
    百度echarts
    linux 内存释放命令
    第二届PHP全球开发者大会(含大会的PPT)
    在CentOS上安装Java开发环境:使用yum安装jdk
  • 原文地址:https://www.cnblogs.com/zqy123/p/5049442.html
Copyright © 2011-2022 走看看