集训
WYT的刷子
题目描述
WYT有一把巨大的刷子,刷子的宽度为M米,现在WYT要使用这把大刷子去粉刷有N列的栅栏(每列宽度都为1米;每列的高度单位也为米,由输入数据给出).使用刷子的规则是:
- 与地面垂直,从栅栏的底部向上刷
- 每次刷的宽度为M米(当剩余栅栏宽度不够M米的话,刷子也可以使用,具体看样例2)
- 对于连续的M列栅栏,刷子从底向上,刷到的高度只能到这M列栅栏的最低高度。
WYT请你回答两个问题:
- 最少有多少个单位面积不能刷到(单位面积为1平米)
- 在满足第一问的条件下,最少刷几次?
输入格式
共两行:
第一行两个整数N和M。
第二行共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\n%d",sum,ans); 64 return 0; 65 }