粟粟的书架

描述

这里写图片描述

输入格式

第一行是三个正整数R, C, M。
接下来是一个 R行C 列的矩阵,从上到下、从左向右依次给出了每本书的 页数Pi,j。
接下来 M行,第 i 行给出正整数x1i, y1i, x2i, y2i, Hi,表示第i 天的指定区域 是﹙x1i, y1i﹚与﹙x2i, y2i﹚间的矩形,总页数之和要求不低于 Hi。
保证 1≤x1i≤x2i≤R,1≤y1i≤y2i≤C。

输出格式

有M行,第i 行回答粟粟在第 i 天时为摘到苹果至少需要 拿取多少本书。
如果即使取走所有书都无法摘到苹果,则在该行输出“Poor QLW” (不含引号)。

样例输入1

5 5 7
14 15 9 26 53
58 9 7 9 32
38 46 26 43 38
32 7 9 50 28
8 41 9 7 17
1 2 5 3 139
3 1 5 5 399
3 3 4 5 91
4 1 4 1 33
1 3 5 4 185
3 3 4 3 23
3 1 3 3 108

样例输出1

6
15
2
Poor QLW
9
1
3

样例输入2

1 10 7
14 15 9 26 53 58 9 7 9 32
1 2 1 9 170
1 2 1 9 171
1 5 1 7 115
1 1 1 10 228
1 4 1 4 4570457
1 1 1 1 11
1 7 1 8 16

样例输出2

6
7
3
10
Poor QLW
1
2

提示

对于 10%的数据,满足 R, C≤10;
对于 20%的数据,满足 R, C≤40;
对于 50%的数据,满足 R, C≤200,M≤200,000;
另有 50%的数据,满足 R=1,C≤500,000,M≤20,000;
对于 100%的数据,满足 1≤Pi,j≤1,000,1≤Hi≤2,000,000,000。


题解

观察数据范围,一半数据的矩阵只有一行,另一半R、C较小。考虑分类讨论。

当矩阵只有一行时,原题变为在一数列中多次询问,每次给定l、r、h,询问从区间[l , r]中选取一些数字,使总和大于或等于h的最小选取个数。考虑主席树。
第i 棵线段树中某一区间[l , r]维护数列前i 个数中,值在[l , r]内的数的个数与总和,用可持久化优化时间、空间。
对于提问[x , y],第y 棵线段树减去第x-1 棵线段树,就可以得到[x , y]中不同区间内的值的数出现的次数与这些数的总和。使用类似二分的方法讨论答案。

当R, C≤200时,考虑预处理优化。
count[i][j][k]记录前i 行j 列中,值大于或等于k 的数的个数,value[i][j][k]记录这些数的总和。
对于每个询问,二分k的值,得到答案。

但是注意,某个值的数不一定全用,因此还要处理答案。具体见代码。


代码

#include <cstdio>
#include <iostream>
#define ll long long
using namespace std;
const ll Q=6000000;
ll n,maxn=1000,m,ls[Q],rs[Q],cnt[Q],a[500005],sum[Q],tot,maxr=1000,q,co[201][201][1005],v[201][201][1005];
void mt(ll now,ll l,ll r)
{
    if(l==r)return;
    ls[now]=++tot;
    rs[now]=++tot;
    ll mid=(l+r)>>1;
    mt(ls[now],l,mid);
    mt(rs[now],mid+1,r);
}
void xiu(ll now,ll last,ll l,ll r,ll v)
{
    cnt[now]=cnt[last]+1,sum[now]=sum[last]+v;
    if(l==r)return;
    ll mid=(l+r)>>1;
    ls[now]=ls[last];
    rs[now]=rs[last];
    if(v<=mid)ls[now]=++tot,xiu(ls[now],ls[last],l,mid,v);
    else rs[now]=++tot,xiu(rs[now],rs[last],mid+1,r,v);
}
ll gs(ll nowl,ll nowr,ll l,ll r,ll v)
{
    if(sum[nowr]-sum[nowl]<v)return 999999999;
    if(l==r)return (v-1)/l+1;
    ll mid=(l+r)>>1,lrs=rs[nowl],rrs=rs[nowr];
    if(sum[rrs]-sum[lrs]>=v)return gs(lrs,rrs,mid+1,r,v);
    else return cnt[rrs]-cnt[lrs]+gs(ls[nowl],ls[nowr],l,mid,v-(sum[rrs]-sum[lrs]));
}
void MoD()
{
    ll j,i,x,y,h;
    n=tot=m;
    mt(0,1,maxr);
    for(i=1;i<=n;i++)
    {
        scanf("%lld",&x);
        xiu(i,i-1,1,maxr,x);
    }
    while(q--)
    {
        scanf("%lld%lld%lld%lld %lld",&i,&x,&j,&y,&h);
        i=gs(x-1,y,1,maxr,h);
        i<999999999?printf("%lld\n",i):printf("Poor QLW\n");
    }
}
int main()
{
    ll k,i,j,x,h,y;
    scanf("%lld%lld%lld",&n,&m,&q);
    if(n==1){
        MoD();
        return 0;
    }
    for(i=1;i<=n;i++)
        for(j=1;j<=m;j++)
        {
            scanf("%lld",&x);
            for(k=1;k<=x;k++)
                co[i][j][k]++,v[i][j][k]+=x;
        }
    for(i=1;i<=n;i++)
        for(j=1;j<=m;j++)
            for(k=1;k<=1000;k++)
            {
                co[i][j][k]+=co[i-1][j][k]+co[i][j-1][k]-co[i-1][j-1][k];
                v[i][j][k]+=v[i-1][j][k]+v[i][j-1][k]-v[i-1][j-1][k];
            }
    while(q--)
    {
        scanf("%lld%lld%lld%lld%lld",&i,&j,&x,&y,&h);
        ll l=1,r=maxn,www,wdf;
        while(l<=r)
        {
            ll mid=(l+r)>>1;
            if(v[x][y][mid]-v[x][j-1][mid]-v[i-1][y][mid]+v[i-1][j-1][mid]>=h)l=mid+1;
            else r=mid-1;
        }
        if(r==0){
            printf("Poor QLW\n");
            continue;
        }
        www=h-(v[x][y][r+1]-v[x][j-1][r+1]-v[i-1][y][r+1]+v[i-1][j-1][r+1]);
        wdf=co[x][y][r+1]-co[x][j-1][r+1]-co[i-1][y][r+1]+co[i-1][j-1][r+1];
        printf("%lld\n",wdf+(www-1)/r+1);
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值