牆上海報
20505吳承樺
牆上海報
2022 1月 APCS
第四題
Zerojudge:
題目敘述
有一個由 n 個木板所組成的柵欄,每個木板的高度為 h[1],h[2]...,h[n],
有 k 張海報要張貼在柵欄上,每張海報的寬度為 w[1],w[2],...w[n] 並且高度均為 1。
若要張貼海報在高度為 x 的高度,則第 i 張海報需要張貼在一個長度為 w[i] 的連續並且高度都不小於 x 的木板上,
且每張海報張貼的高度需要一致、按照順序並不能重疊 (可以相連)。詢問最高可以貼到多高的位置。


想法
二分搜
首先看到找最大最小值
我想到兩種
1.dp
2.二分搜
接著看一下題目的測資
n=2e5
h=1e9
可以推測-> 解答為
O(n\ log\ n)
再來找單調性
二分搜
答案問高度
高度的單調性?
柵欄是從下往上長

所以假設高度i有柵欄 它下面也一定都有
一個高度若可以放完海報
它下面也一定可以放完
111110000
放海報
有幾個關鍵字要注意
1.每張海報張貼的高度需要一致
2.按照順序並不能重疊 (可以相連)
那這邊用的是貪心的想法
貪心
哪裡貪心?
按照順序放:不能挑想放的放
今天從左掃過來
所以如果遇到可以放的不放
那之後還得找地方放
有可能會擋到後面的放
結論:遇到長度符合就放
實作
#include<bits/stdc++.h>
#define maxn 200005
using namespace std;
int h[maxn],w[maxn],n,k;;
int l=1,r,mid;
bool check(int x){
vector<int>v;
int tmp=0;
for(int i=1;i<=n;i++){
if(h[i]>=x){
tmp++;
}
else{
v.push_back(tmp);
tmp=0;
}
}
if(tmp)v.push_back(tmp);
int i=0,j=1;
while(i<v.size() && j<=k){
if(v[i]<w[j]){
i++;
}
else if(v[i]>w[j]){
v[i]-=w[j];
j++;
}else{
i++;
j++;
}
}
if(j==k+1)return true;
return false;
}
int main(){
cin>>n>>k;
for(int i=1;i<=n;i++){
cin>>h[i];
r=max(r,h[i]);
}
for(int i=1;i<=k;i++)cin>>w[i];
while(l<r){
mid=(l+r)/2;
if(check(mid)){
l=mid+1;
}
else{
r=mid;
}
}
cout<<r<<'\n';
}第一份程式碼:10%
bool check(int x){
vector<int>v;
int tmp=0;
for(int i=1;i<=n;i++){
if(h[i]>=x){
tmp++;
}
else{
v.push_back(tmp);
tmp=0;
}
}
if(tmp)v.push_back(tmp);
int i=0,j=1;
while(i<v.size() && j<=k){
if(v[i]<w[j]){
i++;
}
else if(v[i]>w[j]){
v[i]-=w[j];
j++;
}else{
i++;
j++;
}
}
if(j==k+1)return true;
return false;
}
第一份程式碼
checker()
來判斷這個高度可不可以放完
可以:true
else:false
程式邏輯沒有太大的錯誤
但作法過於冗長
繁複
int main(){
cin>>n>>k;
for(int i=1;i<=n;i++){
cin>>h[i];
r=max(r,h[i]);
}
for(int i=1;i<=k;i++)cin>>w[i];
while(l<r){
mid=(l+r)/2;
if(check(mid)){
l=mid+1;
}
else{
r=mid;
}
}
cout<<r<<'\n';
}第一份程式碼
二分搜
也是造成錯誤的原因
這邊的r值是找最大高度
左閉右開寫法
所以r值要++
找到的值是最小的0
題目是要最大的1
輸出r要-1
改完這些其實就可以通過了
但我後來發現有更簡潔的checker寫法
第二份-AC解
#include<bits/stdc++.h>
#define maxn 200005
using namespace std;
int h[maxn],w[maxn],n,k;;
int l=1,r,mid;
bool check(int x){
int cnt=0,j=1;
for(int i=1;i<=n;i++){
if(h[i]>=x)cnt++;
else cnt=0;
if(cnt==w[j]){
cnt=0;
j++;
}
if(j==k+1)return true;
}
return false;
}
int main(){
cin>>n>>k;
for(int i=1;i<=n;i++){
cin>>h[i];
r=max(r,h[i]);
}
for(int i=1;i<=k;i++)cin>>w[i];
r++;
while(l<r){
mid=(l+r)/2;
if(check(mid)){
l=mid+1;
}
else{
r=mid;
}
}
cout<<r-1<<'\n';
}第二份-AC解
bool check(int x){
int cnt=0,j=1;
for(int i=1;i<=n;i++){
if(h[i]>=x)cnt++;
else cnt=0;
if(cnt==w[j]){
cnt=0;
j++;
}
if(j==k+1)return true;
}
return false;
}
原本是把這層高度各個長度存在vector
再去找
但其實找到長度符合現在要放的海報長度
就可以直接放
感謝各位聆聽
題目分享
By wuchanghualeo
題目分享
- 32