bzoj 1926: [Sdoi2010]粟粟的书架
Description
幸福幼儿园 B29 班的粟粟是一个聪明机灵、乖巧可爱的小朋友,她的爱好是画画和读书,尤其喜欢 Thomas H. Co
rmen 的文章。粟粟家中有一个 R行C 列的巨型书架,书架的每一个位置都摆有一本书,上数第i 行、左数第j 列
摆放的书有Pi,j页厚。粟粟每天除了读书之外,还有一件必不可少的工作就是摘苹果,她每天必须摘取一个指定的
苹果。粟粟家果树上的苹果有的高、有的低,但无论如何凭粟粟自己的个头都难以摘到。不过她发现, 如果在脚
下放上几本书,就可以够着苹果;她同时注意到,对于第 i 天指定的那个苹果,只要她脚下放置书的总页数之和
不低于Hi,就一定能够摘到。由于书架内的书过多,父母担心粟粟一天内就把所有书看完而耽误了上幼儿园,于是
每天只允许粟粟在一个特定区域内拿书。这个区域是一个矩形,第 i 天给定区域的左上角是上数第 x1i行的左数
第 y1i本书,右下角是上数第 x2i行的左数第y2i本书。换句话说,粟粟在这一天,只能在这﹙x2i-x1i+1﹚×﹙
y2i-y1i+1﹚本书中挑选若干本垫在脚下,摘取苹果。粟粟每次取书时都能及时放回原位,并且她的书架不会再
撤下书目或换上新书,摘苹果的任务会一直持续 M天。给出每本书籍的页数和每天的区域限制及采摘要求,请你告
诉粟粟,她每天至少拿取多少本书,就可以摘到当天指定的苹果。
solution
不知为何,全程没有注意到值域很小....这也是这题的关键
对于前50分:
\(f[i][j][k]\),表示前i行,前j列,大于等于k的数的和,\(g[i][j][k]\) 表示表示前i行,前j列,大于等于k的数的数量
然后每一个询问二分最小的那本书的厚度就可以了
对于后50分:
前面的数组开不下了,但是只有一行,所以动态开点即可,做法和前面一样
注意:对于多出来的部分要减去.
#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <queue>
#include <cmath>
#define RG register
#define il inline
#define iter iterator
#define Max(a,b) ((a)>(b)?(a):(b))
#define Min(a,b) ((a)<(b)?(a):(b))
using namespace std;
typedef long long ll;
const int N=500005;
int n,m,Q;
namespace T2{
int lim=0,a[205][205],f[205][205][1005];
int g[205][205][1005],t[1005];
inline int qsum(int xl,int yl,int xr,int yr,int k){
return f[xr][yr][k]-f[xl-1][yr][k]-f[xr][yl-1][k]+f[xl-1][yl-1][k];
}
inline int qsize(int xl,int yl,int xr,int yr,int k){
return g[xr][yr][k]-g[xl-1][yr][k]-g[xr][yl-1][k]+g[xl-1][yl-1][k];
}
void main(){
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++){
scanf("%d",&a[i][j]);
f[i][j][a[i][j]]+=a[i][j];
g[i][j][a[i][j]]++;
if(a[i][j]>lim)lim=a[i][j];
t[a[i][j]]++;
}
for(int k=lim;k>=1;k--){
if(t[k]){
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++)
f[i][j][k]+=f[i][j-1][k]+f[i-1][j][k]-f[i-1][j-1][k],
g[i][j][k]+=g[i][j-1][k]+g[i-1][j][k]-g[i-1][j-1][k];
}
}
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
f[i][j][k]+=f[i][j][k+1],g[i][j][k]+=g[i][j][k+1];
}
int xl,yl,xr,yr,sum;
while(Q--){
scanf("%d%d%d%d%d",&xl,&yl,&xr,&yr,&sum);
if(qsum(xl,yl,xr,yr,1)<sum){
puts("Poor QLW");continue;
}
int l=1,r=lim,mid,ret;
while(l<=r){
mid=(l+r)>>1;
if(qsum(xl,yl,xr,yr,mid)>=sum)ret=mid,l=mid+1;
else r=mid-1;
}
int ans=qsize(xl,yl,xr,yr,ret);
int res=qsum(xl,yl,xr,yr,ret)-sum;
ans=ans-res/ret;
printf("%d\n",ans);
}
}
}
namespace T1{
int a[N],totnode=0,root[N],rsum[N];
struct node{
int l,r,val,sz;
}tr[N*20];
inline void ins(int &x,int y,int l,int r,int sa){
x=++totnode;tr[x]=tr[y];tr[x].sz++;
if(l==r){tr[x].val+=l;return ;}
int mid=(l+r)>>1;
if(sa<=mid)ins(tr[x].l,tr[y].l,l,mid,sa);
else ins(tr[x].r,tr[y].r,mid+1,r,sa);
tr[x].val=tr[tr[x].l].val+tr[tr[x].r].val;
}
inline int qry(int x,int y,int l,int r,int sum){
if(l==r){
int res=tr[y].val-tr[x].val-sum;
int ret=tr[y].sz-tr[x].sz;
return ret-res/l;
}
int mid=(l+r)>>1,v=tr[tr[y].r].val-tr[tr[x].r].val;
int size=tr[tr[y].r].sz-tr[tr[x].r].sz;
if(sum<=v)return qry(tr[x].r,tr[y].r,mid+1,r,sum);
return size+qry(tr[x].l,tr[y].l,l,mid,sum-v);
}
void main(){
for(int i=1;i<=m;i++)
scanf("%d",&a[i]),rsum[i]=rsum[i-1]+a[i];
for(int i=1;i<=m;i++)ins(root[i],root[i-1],1,1000,a[i]);
int x,y,z;
while(Q--){
scanf("%d%d%d%d%d",&x,&x,&y,&y,&z);
if(rsum[y]-rsum[x-1]<z)puts("Poor QLW");
else printf("%d\n",qry(root[x-1],root[y],1,1000,z));
}
}
}
int main()
{
scanf("%d%d%d",&n,&m,&Q);
if(n==1)T1::main();
else T2::main();
return 0;
}