题目链接
https://www.lydsy.com/JudgeOnline/problem.php?id=1926
思路
数据范围:50%这样这样……另50%那样那样……
怎么这么毒瘤啊!
还要分开写前50%的数据和后50%的数据的解法!
这道题首先可以观察到:选书肯定是选择厚度尽量大的书(贪心)
对于前50%的数据:
令表示到这个矩形中厚度的书的厚度总和。
表示到这个矩形中厚度的书的个数。
上面两个状态很好转移。
观察到答案具有可二分性,二分选择的书中最小的厚度,注意最后有厚度相同的情况要特殊处理。
对于后50%的数据:
实际上就是直线上给定区间中,满足的的最小值(沿用上面的定义)。
显然可以用主席树维护这个值,注意最后相同的情况同样要预处理。
代码
#include <cstdio>
int r,c,m;
namespace dp
{
const int maxn=200;
const int maxv=1000;
int val[maxn+10][maxn+10][maxv+10],num[maxn+10][maxn+10][maxv+10],p[maxn+10][maxn+10];
inline int getval(int l,int d,int r,int u,int k)
{
return val[r][u][k]-val[l-1][u][k]-val[r][d-1][k]+val[l-1][d-1][k];
}
inline int getnum(int l,int d,int r,int u,int k)
{
return num[r][u][k]-num[l-1][u][k]-num[r][d-1][k]+num[l-1][d-1][k];
}
int solve()
{
for(register int i=1; i<=r; ++i)
{
for(register int j=1; j<=c; ++j)
{
scanf("%d",&p[i][j]);
}
}
for(register int k=1; k<=maxv; ++k)
{
for(register int i=1; i<=r; ++i)
{
for(register int j=1; j<=c; ++j)
{
val[i][j][k]=val[i-1][j][k]+val[i][j-1][k]-val[i-1][j-1][k]+((p[i][j]>=k)?p[i][j]:0);
num[i][j][k]=num[i-1][j][k]+num[i][j-1][k]-num[i-1][j-1][k]+((p[i][j]>=k)?1:0);
}
}
}
while(m--)
{
int a,b,c,d,e,l=1,r=maxv,ans=-1;
scanf("%d%d%d%d%d",&a,&b,&c,&d,&e);
while(l<=r)
{
int mid=(l+r)>>1;
if(getval(a,b,c,d,mid)<e)
{
r=mid-1;
}
else
{
l=mid+1;
ans=mid;
}
}
if(ans==-1)
{
puts("Poor QLW");
}
else
{
printf("%d\n",getnum(a,b,c,d,ans)-(getval(a,b,c,d,ans)-e)/ans);
}
}
return 0;
}
}
namespace pst
{
const int maxn=500000;
const int maxv=1000;
struct node
{
node* son[2];
int val,num;
};
node* root[maxn+10];
int p[maxn+10];
inline int updata(node* now)
{
now->val=now->son[0]->val+now->son[1]->val;
now->num=now->son[0]->num+now->son[1]->num;
return 0;
}
int build(node* now,int l,int r)
{
if(l==r)
{
now->val=now->num=0;
return 0;
}
int mid=(l+r)>>1;
build(now->son[0]=new node(),l,mid);
build(now->son[1]=new node(),mid+1,r);
updata(now);
return 0;
}
node* add(node* now,int l,int r,int pos)
{
node* a=new node();
if(l==r)
{
a->num=now->num+1;
a->val=now->val+pos;
return a;
}
int mid=(l+r)>>1;
if(pos<=mid)
{
a->son[0]=add(now->son[0],l,mid,pos);
a->son[1]=now->son[1];
}
else
{
a->son[0]=now->son[0];
a->son[1]=add(now->son[1],mid+1,r,pos);
}
updata(a);
return a;
}
int query(node* a,node* b,int l,int r,int k)
{
if(l==r)
{
return (k+l-1)/l;
}
int cnt=b->son[1]->val-a->son[1]->val,mid=(l+r)>>1;
if(k<=cnt)
{
return query(a->son[1],b->son[1],mid+1,r,k);
}
else
{
return query(a->son[0],b->son[0],l,mid,k-cnt)+b->son[1]->num-a->son[1]->num;
}
}
int solve()
{
for(register int i=1; i<=c; ++i)
{
scanf("%d",&p[i]);
}
root[0]=new node();
build(root[0],1,maxv);
for(register int i=1; i<=c; ++i)
{
root[i]=add(root[i-1],1,maxv,p[i]);
}
while(m--)
{
int a,b,c,d,e;
scanf("%d%d%d%d%d",&a,&b,&c,&d,&e);
if(root[d]->val-root[b-1]->val<e)
{
puts("Poor QLW");
}
else
{
printf("%d\n",query(root[b-1],root[d],1,maxv,e));
}
}
return 0;
}
}
int main()
{
scanf("%d%d%d",&r,&c,&m);
if(r==1)
{
pst::solve();
}
else
{
dp::solve();
}
return 0;
}