zoukankan      html  css  js  c++  java
  • 1926: [Sdoi2010]粟粟的书架

    1926: [Sdoi2010]粟粟的书架

    Time Limit: 30 Sec  Memory Limit: 552 MB
    Submit: 807  Solved: 321
    [Submit][Status][Discuss]

    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天。给出每本书籍的页数和每天的区域限制及采摘要求,请你告
    诉粟粟,她每天至少拿取多少本书,就可以摘到当天指定的苹果。

    Input

    第一行是三个正整数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。

    Output

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

    Sample Input

    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

    Sample Output

    6
    15
    2
    Poor QLW
    9
    1
    3

    HINT

    对于 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

    Source

    第一轮Day2

    前50%:二位前缀和差分+二分答案

    后50%:主席树维护[l,r]的Σkth+二分答案

    对于第一问(R,C<=200);
      预处理sum[x][y][k],num[x][y][k].表示从(1,1)到(x,y)中大于等于k的数的和与大于等于k的数的个数。
      然后二分最小的数即可。
      注意最后如果最小的数有多个需要稍微调整一下答案。
    对于第二问(R=1):
      我们还是二分最小数。
      判断就变成了询问一段区间内大于等于x的数的和以及它们的个数。
      显然主席树可以处理这个。

    #include<cstdio>
    #define set(x) freopen(#x".in","r",stdin);freopen(#x".out","w",stdout);
    using namespace std;
    int n,m,Q;
    inline int read(){
        int x=0,f=1;char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
        return x*f;
    }
    namespace cas1{
        static const int N=201,Z=1000;
        int sum[N][N][Z],num[N][N][Z];
        void work(){
            for(int i=1,x;i<=n;i++){
                for(int j=1;j<=m;j++){
                    x=read();
                    for(int k=1;k<=1000;k++){
                        sum[i][j][k]=sum[i-1][j][k]+sum[i][j-1][k]-sum[i-1][j-1][k];
                        num[i][j][k]=num[i-1][j][k]+num[i][j-1][k]-num[i-1][j-1][k];
                        if(x>=k) sum[i][j][k]+=x,num[i][j][k]++;
                    }
                }
            }
            for(int x1,x2,y1,y2,h,l,r,mid,ans,cnt1,cnt2;Q--;){
                x1=read();y1=read();x2=read();y2=read();h=read();
                l=1,r=1000,ans=r+1;
                while(l<=r){
                    mid=l+r>>1;
                    if(sum[x2][y2][mid]-sum[x1-1][y2][mid]-sum[x2][y1-1][mid]+sum[x1-1][y1-1][mid]>=h){
                        l=mid+1;ans=mid;
                    }
                    else{
                        r=mid-1;
                    }
                }
                if(ans>1000) puts("Poor QLW");
                else{
                    cnt1=sum[x2][y2][ans]-sum[x1-1][y2][ans]-sum[x2][y1-1][ans]+sum[x1-1][y1-1][ans]-h;
                    cnt2=num[x2][y2][ans]-num[x1-1][y2][ans]-num[x2][y1-1][ans]+num[x1-1][y1-1][ans];
                    printf("%d
    ",cnt2-cnt1/ans);
                }
            }
        }
    }
    namespace cas2{
        static const int N=5e5+5,M=N*20;
        int sz,tot[N],sum[M],siz[M],ls[M],rs[M],root[N];
        void insert(int &k,int last,int l,int r,int x){
            k=++sz;
            siz[k]=siz[last]+1;
            sum[k]=sum[last]+x;
            if(l==r) return ;
            ls[k]=ls[last];
            rs[k]=rs[last];
            int mid=l+r>>1;
            if(x<=mid) insert(ls[k],ls[last],l,mid,x);
            else insert(rs[k],rs[last],mid+1,r,x);
        }
        int query(int k,int last,int l,int r,int kth){
            if(l==r) return (sum[k]-sum[last])/(siz[k]-siz[last])*kth;
            int mid=l+r>>1,cnt=siz[ls[k]]-siz[ls[last]];
            if(kth<=cnt) return query(ls[k],ls[last],l,mid,kth);
            return sum[ls[k]]-sum[ls[last]]+query(rs[k],rs[last],mid+1,r,kth-cnt);
        }
        void work(){
            for(int i=1,x;i<=m;i++){
                x=read(); 
                insert(root[i],root[i-1],1,1000,x);
                tot[i]=tot[i-1]+x;
            }
            for(int x1,x2,y1,y2,h,l,r,mid,up,ans,K;Q--;){
                x1=read();y1=read();x2=read();y2=read();h=read();
                if(tot[y2]-tot[y1-1]<h){puts("Poor QLW");continue;}
                l=1,r=up=y2-y1+1,ans=r;
                while(l<=r){
                    mid=l+r>>1;K=up-mid+1;
                    if(tot[y2]-tot[y1-1]-query(root[y2],root[y1-1],1,1000,K)>=h){
                        r=mid-1;ans=mid-1;
                    }
                    else{
                        l=mid+1;
                    }
                }
                printf("%d
    ",ans);
            }
        }
    }
    int main(){
        set(susu);
        n=read();m=read();Q=read();
        if(n<=200&&m<=200)
            cas1::work();
        else
            cas2::work();
        return 0;
    }
  • 相关阅读:
    【算法学习笔记】76.DFS 回溯检测 SJTU OJ 1229 mine
    【算法学习笔记】75. 动态规划 棋盘型 期望计算 1390 畅畅的牙签盒(改)
    【算法学习笔记】74. 枚举 状态压缩 填充方案 SJTU OJ 1391 畅畅的牙签袋(改)
    【算法学习笔记】73.数学规律题 SJTU OJ 1058 小M的机器人
    【算法学习笔记】72.LCS 最大公公子序列 动态规划 SJTU OJ 1065 小M的生物实验1
    【算法学习笔记】71.动态规划 双重条件 SJTU OJ 1124 我把助教团的平均智商拉低了
    【算法学习笔记】70.回文序列 动态规划 SJTU OJ 1066 小M家的牛们
    【算法学习笔记】69. 枚举法 字典序处理 SJTU OJ 1047 The Clocks
    【算法学习笔记】68.枚举 SJTU OJ 1272 写数游戏
    【算法学习笔记】67.状态压缩 DP SJTU OJ 1383 畅畅的牙签袋
  • 原文地址:https://www.cnblogs.com/shenben/p/6613718.html
Copyright © 2011-2022 走看看