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;
}

posted @ 2017-12-09 17:20  PIPIBoss  阅读(199)  评论(0编辑  收藏  举报