zoukankan      html  css  js  c++  java
  • 单调栈之WYT的刷子

    好久没更题解了(改题困难的我)

    题目描述

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

    使用刷子的规则是:

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

    WYT请你回答两个问题:

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

    输入格式

    共两行:
    第一行两个整数N和M。
    第二行共N个整数,表示N列栅栏的高度

    输出格式

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

    样例

    输入

    5 3
    5 3 4 4 5
    

    输出

    3
    2
    

    样例对应解释

    高度分别为 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.

    思路

    • 这道题当时真的没有想出来,直接暴力模拟拿了点分,这道题的核心在于维护单调栈,用于求解每块木板向右(向左)延伸的长度,拿向右来说,我们维护单调递增的栈,当栈顶元素的长度小于要放入的元素,则正常入栈,top++,如果栈不为空且栈顶元素(假设为sta[top])大于扫描到的元素(假设为i),对栈顶元素执行出栈操作,然后可得sta[top]向右延伸的距离为r[sta[top]]=i-sta[top],r数组维护向右延伸的长度,同理可求得左边延伸长度;
    • 处理完l和r数组后,对于木板i,其延伸距离为l[i]+r[i]-1,判断其与刷子宽度的大小,大于则可以刷到,用flag标记,小于则不能。然后枚举每一块木板,维护mh数组为第i块木板能被刷到的长度,如果被标记过,则mh[i]=h[i],如果不能,则mh[i]=mh[i-1],用长度和减去可以被刷到的部分即为ans1;
    • 对于每一部分(能被刷到的的长度相等),贪心处理,用其宽度除以刷子宽度,累加得ans2;

    附上代码一份

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn=1e6+10;
    long long v[maxn],mh[maxn],sum,r[maxn],l[maxn];
    long long n,m;
    bool flag[maxn];
    inline int read(){
    	int s=0;
    	char ch=getchar();
    	while(ch<'0'||ch>'9')ch=getchar();
    	while(ch>='0'&& ch<='9')s=(s<<3)+(s<<1)+(ch^48),ch=getchar();
    	return s;
    }
    long long sta[maxn],top,h[maxn];
    int main(){
    	n=read(),m=read();
    	for(int i=1;i<=n;i++){
    		h[i]=read();
    		sum+=h[i];
    	}
    	for(int i=1;i<=n+1;i++){
    		while(top && h[i]<h[sta[top]]){
    			r[sta[top]]=i-sta[top];
    			top--;
    		}
    		sta[++top]=i;
    	}
    	for(int i=n;i>=0;i--){
    		while(top && h[i]<h[sta[top]]){
    			l[sta[top]]=sta[top]-i;
    			top--;
    		}
    		sta[++top]=i;
    	}
    	for(int i=1;i<=n;i++){
    		if(l[i]+r[i]-1>=m)flag[i]=true;
    	}
    	for(int i=1;i<=n;i++){
    		if(flag[i])mh[i]=h[i];
    		else{
    			mh[i]=mh[i-1];
    		}
    	}
    	for(int i=n;i>0;i--){
    		if(!flag[i])mh[i]=max(mh[i],mh[i+1]);
    	sum-=mh[i];
    	}
    	cout<<sum<<endl;
    	long long k=2,ans=0;
    	while(k<=n+1){
    		int cnt=1;
    		while(k<=n+1 && mh[k]==mh[k-1]){
    			++cnt;
    			++k;
    		}
    		ans+=cnt/m;
    		if(cnt%m)++ans;
    		++k;
    	}
    	cout<<ans<<endl;
    }	
    
    
  • 相关阅读:
    linux--->curl
    linux--->定时任务
    php--->无限级分类
    php--->自己封装的简易版mvc框架
    php--->单例模式封装mysql操作类
    Linux使用退格键时出现^H ^?解决方法
    错误日志
    linux下redis服务器安装使用 安装php的redis扩展 安装laravel下的redis
    php system()
    laravel redis的使用
  • 原文地址:https://www.cnblogs.com/soda-ma/p/13226798.html
Copyright © 2011-2022 走看看