• bzoj1926: [Sdoi2010]粟粟的书架


    题目链接

    bzoj1926: [Sdoi2010]粟粟的书架

    题解

    看数据范围,发现这是两道题......0.5倍经验
    对于R,C <= 200
    前缀和+二分
    前缀num[i][j][k]维护矩形(1,1)(i,j)中比k大的数有几个
    sum[i][j][k] 维护维护矩形(1,1)(i,j)中比k大的数和为多少
    在矩形中二分到k+1最后暴力填k
    对于第二问变成了序列
    二分取几个数(k)+主席树,用主席树维护权值,在主席树中取最大的k个数查看时否满足

    代码

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    
    using std::max;
    int R,C,m;
    inline int read () {
        int x = 0,f = 1;
        char c = getchar ();
        while(c < '0' || c > '9'){if(c == '-') f = -1; c = getchar();}
        while(c <= '9' && c >= '0') x = x * 10 + c - '0',c = getchar();
        return x*f;
    }
    namespace Solve_1 {
    #define maxn 207
        int a[maxn][maxn];
        int num[maxn][maxn][1007],sum[maxn][maxn][1007];
        int Max = 0;
        int  get_sum(int a,int b,int c,int d,int v) {
            return sum[c][d][v] - sum[a][d][v] - sum[c][b][v] + sum[a][b][v];
        }
        int  get_num(int a,int b,int c,int d,int v) {
            return num[c][d][v] - num[a][d][v] - num[c][b][v] + num[a][b][v];
        }
        int Get_Ans(int a,int b,int c,int d,int k,int need) {
            int ret = get_num(a,b,c,d,k+1);
            need -= get_sum(a,b,c,d,k+1);
            if(need>=0) {
                int num = need / k;
                ret += num; 
                need -= num * k;if(need > 0)ret++,need -= k;
            }
            return ret;
        }
        bool judge (int a,int b,int c,int d,int mid,int h) {
            //printf("%d
    ",get_sum(a,b,c,d,mid));
            return get_sum(a,b,c,d,mid) > h ? true : false;
        }
        void work_Main() {
            memset(sum,0,sizeof sum);
            memset(num,0,sizeof num);
            for(int i = 1;i <= R;++ i) 
                for(int j = 1;j <= C;++ j) 
                    a[i][j] = read(),Max = max (Max,a[i][j]);
            /*for(int i = 1;i <= R;++i) 
                for(int j = 1;j <= C;++ j) 
                    for(int k = 1;k <= Max;++k) 
                        sum[i][j][k]= num[i][j][k] = 0;*/
            for(int k = 0;k <= Max;++ k) 
                for(int i = 1;i <= R;++ i) 
                    for(int j = 1;j <= C;++ j) {
                        //printf("%d
    ",sum[i][j][k]);
                        num[i][j][k] = num[i-1][j][k] + num[i][j-1][k] - num[i-1][j-1][k] + (a[i][j] >= k ?  1: 0);
                        sum[i][j][k] = sum[i-1][j][k] + sum[i][j-1][k] - sum[i-1][j-1][k] + (a[i][j] >= k ? a[i][j] : 0);
                    }
            for(int a,b,c,d,h;m --;) {
                a = read() -1 ,b = read() -1,c = read(),d = read(),h = read(); 
                if(get_sum(a,b,c,d,0) < h) {
                    puts("Poor QLW");continue;
                }
                int l = 1,r = Max,ans = 0; 
                while(l <= r) {
                    int mid = l + r >> 1;
                    if(judge(a,b,c,d,mid,h)) l = mid + 1,ans = mid;
                    else r = mid - 1;
                }
                if(!ans) ans = 1;
                if(ans) printf("%d
    ",Get_Ans(a,b,c,d,ans,h));
            }
        }
    #undef maxn
    }	
    namespace Solve_2{
    #define maxn 500007
    #define lc t[x].ch[0]
    #define rc t[x].ch[1]
        int a[maxn],tot = 0;
        int root[maxn];
        struct ChairMan_Tree {
            int ch[2],sum,sz;
            ChairMan_Tree() {
                sum=sz=ch[1]=ch[0]=0;
            }
        };
        ChairMan_Tree t[maxn << 4];
        int Max = 0;
        void update(int x) {
            t[x].sum = t[lc].sum + t[rc].sum;
        }
        void Insert(int pre,int &x,int l,int r,int p) {
            t[x = ++ tot].sz = t[pre].sz + 1,t[x].sum = t[pre].sum;
            if(l == r) {
                t[x].sum += p; return ;
            }
            int mid = l + r >> 1;
            if( p<=mid ) rc = t[pre].ch[1],Insert(t[pre].ch[0],lc,l,mid,p);
            else lc = t[pre].ch[0],Insert(t[pre].ch[1],rc,mid + 1,r,p);
            update(x);
        }
        int query(int pre,int x,int l,int r,int k) {
            if(t[x].sz <= t[pre].sz + k) return t[x].sum - t[pre].sum;
            if(l == r) return (t[x].sum - t[pre].sum) / (t[x].sz - t[pre].sz) *k;
            int mid = l + r >> 1;
            if(t[rc].sz >= t[t[pre].ch[1]].sz + k) return query(t[pre].ch[1],rc,mid + 1,r,k);
            else return query(t[pre].ch[0],lc,l,mid,k - t[rc].sz + t[t[pre].ch[1]].sz) + t[rc].sum - t[t[pre].ch[1]].sum;
        }
        void Work_Main() {
            Max = 1000;
            for(int i = 1;i<= C;++ i) 
                a[i] = read();//,Max = max(a[i],Max);
            for(int i = 1;i <= C;++ i) Insert(root[i-1],root[i],1,Max,a[i]);			
            for(int l,r,a,b,c,d,h;m --;) {
                a = read(),b = read() -1,c = read(),d = read(),h = read();
                l = 1,r = d - b + 1;
                while(l < r) {
                    int mid = l + r >> 1; 
                    if(query(root[b],root[d],1,Max,mid) >= h) r = mid;
                    else l = mid + 1;
                }
                if(r == d - b + 1) puts("Poor QLW");
                else printf("%d
    ",l);
            }
        }
    }
    int main() {
        R=read(),C=read(),m=read(); 
        if(R!=1) Solve_1::work_Main(); 
        else Solve_2::Work_Main();
    }
        
    
    
  • 相关阅读:
    DbHelper数据操作类
    获取cpu序列号,硬盘ID,网卡MAC地址
    用户必备资料 103个Windows XP运行命令
    在Web.config配置文件中自定义配置节点
    Microsoft.NET PetShop4架构与技术分析
    数字转英文(货币)大写(vb)
    如何计算dba_tables中的avg_row_len.
    行选移与行链接的介绍
    如何使用动态SQL
    如何导致全表扫描原因
  • 原文地址:https://www.cnblogs.com/sssy/p/8708509.html
Copyright © 2020-2023  润新知