问题描述
蒜厂有一个 h×w 的矩形公告板,其中 h 是高度,w 是宽度。
现在有若干张 1×Wi 的公告, Wi 是宽度,公告只能横着放,即高度为 1 的边垂直于水平面,且不能互相有重叠,每张公告都要求尽可能的放在最上面的合法的位置上。
若可以放置,输出每块可放置的位置的行号;若不存在,输出 −1。行号由上至下分别为 1,2,…,h。
输入格式
第一行三个整数 h,w,n (1≤h,w≤10^9;1≤n≤200,000) 。
接下来 n 行,每行一个整数 Wi(1≤Wi≤109) 。
输出格式
输出n 行,一行一个整数。
样例输入
3 5 5
2
4
3
3
3123456
样例输出
1
2
1
3
-1
这两种方法在求解这道题上的效果并没有很大的区别,都是从s[1]向下找。如果用c++中的cin、cout输入输出,最后一个样例都会超时(提醒我们:能用scanf和printf就尽量用这两个)
方法一:直接暴力求解
#include<bits/stdc++.h>
using namespace std;
const int N=200010;
int s[4*N];
int h,w,n,wd;
void check(){
for(int i=1;i<=h;i++){
if(s[i]>=wd){
s[i]-=wd;
printf("%d\n",i);
return;
}
}
printf("-1\n");
}
int main(){
scanf("%d%d%d",&h,&w,&n);
for(int i=1;i<=h;i++){
s[i]=w;
}
for(int i=1;i<=n;i++){
scanf("%d",&wd);
check();
}
return 0;
}
方法二:线段树
#include<bits/stdc++.h>
using namespace std;
const int N=200010;
int s[4*N];
int h,w,n;
int flag=0;
void buildtree(int p,int l,int r){//建树
if(l==r){//将每个叶子节点都赋为最大宽度w
s[p]=w;
return;
}
int mid=(l+r)/2;
buildtree(p*2,l,mid);//建立左子树
buildtree(p*2+1,mid+1,r);//建立右子树
s[p] = max(s[p*2],s[p*2+1]) ;//更新父亲信息
return;
}
void modify(int p,int l,int r,int ww){
if(l==r){
s[p]-=ww;
flag=1;
cout<<l<<endl;
return;
}
int mid=(l+r)/2;
if(s[(p<<1)]>=ww){
modify((p<<1),l,mid,ww);
}
if(s[(p<<1)+1]>=ww&&!flag){
modify((p<<1)+1,mid+1,r,ww);
}
s[p]=max(s[(p<<1)],s[(p<<1)+1]);
return;
}
int main(){
scanf("%d%d%d",&h,&w,&n);
buildtree(1,1,h);
int wd;
for(int i=1;i<=n;i++){
scanf("%d",&wd);
flag=0;
if(s[1]>=wd)
modify(1,1,h,wd);
if(!flag){
printf("-1\n");
}
}
return 0;
}