暑假集訓Day 9 WYT的刷子

題目大意

WYT有一把巨大的刷子,刷子的寬度爲M米,如今WYT要使用這把大刷子去粉刷有N列的柵欄(每列寬度都爲1米;每列的高度單位也爲米,由輸入數據給出)。c++

使用刷子的規則是:算法

1.與地面垂直,從柵欄的底部向上刷
2.每次刷的寬度爲M米(當剩餘柵欄寬度不夠M米的話,刷子也可使用,具體看樣例2)
3.對於連續的M列柵欄,刷子從底向上,刷到的高度只能到這M列柵欄的最低高度。數組

WYT請你回答兩個問題:spa

1.最少有多少個單位面積不能刷到(單位面積爲1平米)
2.在知足第一問的條件下,最少刷幾回?code

輸入格式

共兩行:隊列

第一行兩個整數N和M。get

第二行共N個整數,表示N列柵欄的高度it

輸出格式

一行,兩個整數,分別爲最少剩餘的單位面積數量和最少刷的次數。class

樣例

樣例輸入

5 3
5 3 4 4 5

樣例輸出

3
2

算法分析

  • 先來求解第一問: 如何判斷當前位置的柵欄是否能夠刷完呢? 根據題意咱們能夠知道在一個刷子的範圍內 是由最矮的柵欄控制高度的 因此若是當前位置的柵欄向左向右的柵欄不低於它的個數大於等於M,則當前位置的柵欄就能夠刷完
  • 因此用兩個單調的隊列來維護一下當前位置能夠向右延伸的距離與能夠向左延伸的距離
int tail = -1;//求向右延伸的寬度
for(int i = 1;i <= n+1;++i){//枚舉到n+1可使前n個都出列
	while(tail >= 0 && a[i] < a[que[tail]]){//維護一個單調不上升的隊列 若是第i個的高度比前一個矮了就出隊
		r[que[tail]] = i - que[tail];//r是當前節點所能向右延伸的距離
		--tail;
	}
	que[++tail] = i;//把當前位置入隊
}
tail = -1;//求向左延伸的寬度
for(int i = n;i >= 0;--i){
	while(tail >= 0 && a[i] < a[que[tail]]){
		l[que[tail]] = que[tail] - i;
		--tail;
	}
	que[++tail] = i;
}
for(int i = 1;i <= n;++i){
	if(l[i] + r[i] - 1 >= m)flag[i] = true;//flag標記能刷完
}
  • 而後就是求不能刷到的方塊個數了 咱們能夠用一個數組mh表示當前方格能刷到的最高位置 遞推處理一下:mh[i] = mdi-1(很顯然的關係式 要麼能刷完,若是刷不完的話確定就等於前面的矩形能刷的高度 不然的話若是大於那會出現刷子卡在前面那個過不來 若是小於那麼前面那個就會被它卡住~~語言表達有點困難 請盡力理解一下 ~~)而後再從右向左處理一遍(由於有可能能夠將當前位置安在右邊一塊兒刷完可能會更優)
  • 已知mh那顯然不能刷的方塊個數也就出來了 見代碼
for(int i = 1;i <= n;++i){
	if(flag[i])mh[i] = a[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];
}
  • 要求刷的次數 直接貪心求解就行了(由於若是能刷高必定會往高裏刷 若是幾個同樣高度的能一塊兒刷 那就確定會一塊兒刷掉)
int k = 2,ans = 0;//k=2是由於第一個方塊不管如何都要花費一次去刷
while(k <= n){//當前刷到第k個方塊了
	int cnt = 1;//第一個方塊已經花費一次去刷了
	while(k < n && mh[k] == mh[k+1]){//若是當前的能刷的最高高度和下一個能刷的最高高度同樣 就一塊兒刷掉
		cnt++;k++;
	}
	ans += cnt/m;
	if(cnt % m)++ans;//保證向上取整
	++k;//進入下個矩形
}

代碼展現

#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e7+10;
typedef long long ll;
ll a[maxn],sum,r[maxn],l[maxn],mh[maxn],que[maxn],flag[maxn];

int main(){
	int n,m;scanf("%d%d",&n,&m);
	for(int i = 1;i <= n;++i){scanf("%lld",&a[i]);sum += a[i];}
	int tail = -1;
	for(int i = 1;i <= n+1;++i){
		while(tail >= 0 && a[i] < a[que[tail]]){
			r[que[tail]] = i - que[tail];
			--tail;
		}
		que[++tail] = i;
	}
	tail = -1;
	for(int i = n;i >= 0;--i){
		while(tail >= 0 && a[i] < a[que[tail]]){
			l[que[tail]] = que[tail] - i;
			--tail;
		}
		que[++tail] = 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] = a[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];
	}
	int k = 2,ans = 0;
	while(k <= n){
		int cnt = 1;
		while(k <= n+1 && mh[k] == mh[k-1]){
			cnt++;k++;
		}
		ans += cnt/m;
		if(cnt % m)++ans;
		++k;
	}
	printf("%lld\n%d",sum,ans);
	return 0;
}
相關文章
相關標籤/搜索