2018.9南京网络预选赛(J)

传送门:Problem J

https://www.cnblogs.com/violet-acmer/p/9720603.html

 

变量解释:

  need[ i ] : 第 i 个房间含有的旧灯泡个数。

  remain[ i ] : 第 i 月后,换完满足条件的房间的旧灯泡后剩余节能灯泡的个数。

  total[ i ] : 前 i 个月换灯泡的房间数。

题意:

  有n个房间,每个房间都有need[ i ] 个旧灯泡等着男主角去换,男主角Lpl每个月都会购买m个节能灯泡,按照输入顺序给房间换灯泡,如果当前房间满足条件,则全部换完,不满足,跳到下一个房间,重复当前步骤。

  如果当前房间并不能将新灯泡全部用完,则留着新灯泡给下个月使用。

  有q个询问,每个询问给你一个值mon,代表当前月,输出[1,mon]月换灯泡的房间个数,以及还玩灯泡后新灯泡的剩余个数。

题解:

  最简单的方法就是暴力,从第一个月开始枚举所有的房间,知道所有的房间都换完,或来到询问的最大月份,毋庸置疑,此操作的时间复杂度为O(max_mon*n),而本题的数据范围为1~1e5,显然会超时,1e5需要的实践复杂度至多为n*logn。

  换个思路,考虑一下线段树。

  线段树中当前结点的val值存储的是左右孩子中需要换灯泡的最小值,对于第 i 个月份,优先更新满足条件的左孩子区间,当左孩子不满足条件是,回溯到右孩子区间,直到不满足条件跳出递归。

  对于满足条件的房间,在更换完灯泡后,将其val值设为最大值INF,并向上更新其父亲的val。

  具体细节,看代码............

AC代码:

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 using namespace std;
 5 #define ls(x) ((x)<<1)
 6 #define rs(x) ((x)<<1 | 1)
 7 #define INF 0x3f3f3f3f
 8 const int maxn=1e5+50;
 9 
10 int need[maxn];
11 int remain[maxn];
12 int total[maxn];
13 int lamps;//当前月份的新灯泡数量
14 int sum;//前 i 个月可以换灯泡的房间数
15 struct Node1
16 {
17     int l,r;
18     int val;
19     int mid(){
20         return l+((r-l)>>1);
21     }
22 }segTree[4*maxn];
23 void pushUp(int pos)
24 {
25     segTree[pos].val=min(segTree[ls(pos)].val,segTree[rs(pos)].val);
26 }
27 void buildTree(int l,int r,int pos)
28 {
29     segTree[pos].l=l,segTree[pos].r=r;
30     if(l == r)
31     {
32         segTree[pos].val=need[l];
33         return ;
34     }
35     int mid=l+((r-l)>>1);
36     buildTree(l,mid,ls(pos));
37     buildTree(mid+1,r,rs(pos));
38     pushUp(pos);
39 }
40 void update(int pos,int i)
41 {
42     if(segTree[pos].l == segTree[pos].r && segTree[pos].val <= lamps)
43     {
44         lamps -= segTree[pos].val;
45         segTree[pos].val=INF;//当前房间换完灯泡后,设置成最大值
46         pushUp(pos>>1);//向上更新
47 
48         sum++;//可以更换的房间数 ++
49         return ;
50     }
51     if(segTree[pos].val <= lamps)
52     {
53         if(segTree[ls(pos)].val <= lamps)//优先判断左孩子是否满足条件
54             update(ls(pos),i);
55         update(rs(pos),i);
56     }
57     pushUp(pos>>1);//向上更新
58 }
59 void init()
60 {
61     lamps=0;
62     sum=0;
63     memset(remain,0,sizeof(remain));
64     memset(total,0,sizeof(total));
65 }
66 int main()
67 {
68     int n,m;
69     while(~scanf("%d%d",&n,&m))
70     {
71         init();
72         for(int i=1;i <= n;++i)
73             scanf("%d",need+i);
74         buildTree(1,n,1);
75 
76         for(int i=1;i <= 100000;++i)//月份最多是100000
77         {
78             lamps=remain[i-1]+m;
79             update(1,i);
80             remain[i]=(total[i-1] == n ? remain[i-1]:lamps);//更新当前月份的剩余新灯泡数量
81             total[i]=sum;//更新前 i 个月可以更换的房间数
82         }
83         int q;
84         scanf("%d",&q);
85         for(int i=1;i <= q;++i)
86         {
87             int mon;
88             scanf("%d",&mon);
89             printf("%d %d\n",total[mon],remain[mon]);
90         }
91     }
92 }
View Code
posted @ 2018-09-28 20:31  HHHyacinth  阅读(208)  评论(0编辑  收藏  举报