集训

WYT的刷子

题目描述

WYT有一把巨大的刷子,刷子的宽度为M米,现在WYT要使用这把大刷子去粉刷有N列的栅栏(每列宽度都为1米;每列的高度单位也为米,由输入数据给出).使用刷子的规则是:

  1. 与地面垂直,从栅栏的底部向上刷
  2. 每次刷的宽度为M米(当剩余栅栏宽度不够M米的话,刷子也可以使用,具体看样例2
  3. 对于连续的M列栅栏,刷子从底向上,刷到的高度只能到这M列栅栏的最低高度。

WYT请你回答两个问题:

  1. 最少有多少个单位面积不能刷到(单位面积为1平米)
  2. 在满足第一问的条件下,最少刷几次?

   

输入格式

共两行:

第一行两个整数NM

第二行共N个整数,表示N列栅栏的高度

输出格式

一行,两个整数,分别为最少剩余的单位面积数量和最少刷的次数。

样例输入1

5 3

5 3 4 4 5

样例输出1

3

2

样例输入2

10 3

3 3 3 3 3 3 3 3 3 3

样例输出2

0

4样例输入3

7 4

1 2 3 4 3 2 1

样例输出3

4

4

样例1解释

高度分别为 5 3 4 4 5 如上:

黄色的方块表示共有3个单位面积没刷上

绿色的数据范围与提示

30%的数据:N<=10^3

50%的数据:N<=10^5

100%的数据:1<=N<=10^6, 1<=M<=10^6,N>=M, 每列栅栏的高度<=10^6.

框和红色的框表示一共刷了两次

 1 #include<cstdio>
 2 #include<algorithm>
 3 using namespace std;
 4 const int maxn=1e6+10;
 5 int a[maxn],r[maxn],l[maxn],mh[maxn],st[maxn],q[maxn];
 6 int main(){
 7     int n,m;
 8     long long sum=0;
 9     scanf("%d%d",&n,&m);
10     for(int i=1;i<=n;i++){
11        scanf("%d",&a[i]);
12        sum+=a[i];
13     }
14     int head=0;
15     int tail=-1;//这样初始化只是为了让a[1]进栈
16     for(int i=1;i<=n;i++){
17         while(head<=tail&&a[i]<a[st[tail]]){//当a[i]<a[栈顶]时栈顶不能全部向右延伸
18              r[st[tail]]=i-st[tail];
19              tail--;
20         }
21         st[++tail]=i;
22     }
23     while(tail>=0){//栈中其他出栈
24        r[st[tail]]=n-st[tail]+1;
25        tail--;
26     }
27    head=0;
28     tail=-1;
29     for(int i=n;i>=0;i--){
30         while(head<=tail&&a[i]<a[q[tail]]){
31             l[q[tail]]=q[tail]-i;
32             tail--;
33         }
34         q[++tail]=i;
35     }//左边界同上
36     int flag[maxn];
37     for(int i=1;i<=n;i++){
38         if(r[i]+l[i]-1>=m) flag[i]=1;//记得-1,因为寻找左右边界时都加上了自己
39     }
40     for(int i=1;i<=n;i++){
41         if(flag[i]==1){
42             mh[i]=a[i];
43         }
44         else{
45             mh[i]=mh[i-1];//不能写成mh[i]=a[i-1],因为可能第i-1也不能全部被刷玩
46         }
47     }
48     for(int i=n;i>=1;i--){//从右边扫一遍
49         if(flag[i]==0) mh[i]=max(mh[i],mh[i+1]);
50         sum-=mh[i];
51     }
52     int k=2,ans=0;
53     while(k<=n+1){//n+1保证全部都被扫到
54          int cnt=1;
55          while(k<=n+1&&mh[k]==mh[k-1]){
56               cnt++;
57               k++;
58          }
59          k++;
60          ans+=cnt/m;
61          if(cnt%m!=0) ans++;
62     }
63     printf("%lld
%d",sum,ans);
64     return 0;
65 }
View Code
原文地址:https://www.cnblogs.com/HZOIDJ123/p/13227231.html