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

    1926: [Sdoi2010]粟粟的书架

    https://www.lydsy.com/JudgeOnline/problem.php?id=1926

    分析:

      二分 前缀和 主席树。

      分成两问做,第一问预处理一个前缀和val[i][j][k],矩阵左上角(1,1),右下角(i,j),大于等于k的和,同样记录有多少个数num。二分最小的数。

      第二问,建立主席树,同样二分一个最小值k,然后求出大于等于k的和。判断。

      注意判断以下边界,大于等于k的可能全选上。

    代码: 

      1 #include<cstdio>
      2 #include<iostream>
      3 #include<algorithm>
      4 #include<cmath>
      5 using namespace std;
      6 
      7 inline int read() {
      8     int x=0,f=1;char ch=getchar();for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1;
      9     for (;isdigit(ch);ch=getchar())x=x*10+ch-'0';return x*f;
     10 }
     11  
     12 int n,m,T;
     13  
     14 namespace work1 {
     15     const int N = 205;
     16     int val[N][N][1002], num[N][N][1002], p[N][N], Mx;
     17      
     18     int getval(int a1,int b1,int a2,int b2,int k) {
     19         return val[a2][b2][k] - val[a1-1][b2][k] - val[a2][b1-1][k] + val[a1-1][b1-1][k];
     20     }
     21     int getnum(int a1,int b1,int a2,int b2,int k) {
     22         return num[a2][b2][k] - num[a1-1][b2][k] - num[a2][b1-1][k] + num[a1-1][b1-1][k];
     23     }
     24     void solve() {
     25         for (int i=1; i<=n; ++i) 
     26             for (int j=1; j<=m; ++j) 
     27                 p[i][j] = read(), Mx = max(Mx, p[i][j]);
     28         for (int k=0; k<=Mx; ++k) 
     29             for (int i=1; i<=n; ++i) 
     30                 for (int j=1; j<=m; ++j) {
     31                     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);
     32                     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);
     33                 }
     34         while (T--) {
     35             int a1 = read(), b1 = read(), a2 = read(), b2 = read(), h = read();
     36             if (getval(a1, b1, a2, b2, 0) < h) {
     37                 puts("Poor QLW"); continue ;
     38             }
     39             int L = 0, R = Mx, ans = -1;
     40             while (L <= R) {
     41                 int mid = (L + R) >> 1;
     42                 if (getval(a1, b1, a2, b2, mid) >= h) ans = mid, L = mid + 1;
     43                 else R = mid - 1;
     44             }
     45             if (ans == -1) {
     46                 puts("Poor QLW"); continue ;
     47             }
     48             printf("%d
    ",getnum(a1, b1, a2, b2, ans) - (getval(a1, b1, a2, b2, ans) - h) / ans);
     49             // 大于等于ans的并不一定取完。一共需要大于等于h,所以减去使得大于h后的最多的数,就是ans 
     50         }
     51     }
     52 }
     53 namespace work2{
     54     const int N = 500005;
     55     int ls[N*20], rs[N*20], sum[N*20], siz[N*20], Root[N], CntNode;
     56      
     57     void update(int l,int r,int &rt,int last,int p) { // 权值线段树,p既是坐标也是权值 
     58         rt = ++CntNode;
     59         sum[rt] = sum[last] + p;
     60         siz[rt] = siz[last] + 1;
     61         int mid = (l + r) >> 1;
     62         if (l == r) return ;
     63         if (p <= mid) {
     64             rs[rt] = rs[last];
     65             update(l, mid, ls[rt], ls[last], p);
     66         }
     67         else {
     68             ls[rt] = ls[last];
     69             update(mid+1, r, rs[rt], rs[last], p);
     70         }
     71     }
     72     int query(int l,int r,int Head,int Tail,int x) {
     73         if (l == r) {
     74             return ceil((double)x/l); // 向上取整,保证大于等于x 
     75             return x / l;
     76         }
     77         int mid = (l + r) >> 1, t = sum[rs[Tail]] - sum[rs[Head]];
     78         if (x > t) return siz[rs[Tail]] - siz[rs[Head]] + query(l, mid, ls[Head], ls[Tail], x-t);
     79         return query(mid+1, r, rs[Head], rs[Tail], x);
     80     }
     81      
     82     void solve() {
     83         for (int i=1; i<=m; ++i) {
     84             int x = read();
     85             update(1, 1000, Root[i], Root[i-1], x);
     86         }
     87         while (T--) {
     88             int a1 = read(), b1 = read(), a2 = read(), b2 = read(), h = read();
     89             if (sum[Root[b2]] - sum[Root[b1-1]] < h) {
     90                 puts("Poor QLW"); continue ;
     91             }
     92             printf("%d
    ",query(1, 1000, Root[b1-1], Root[b2], h));
     93         }
     94     }
     95 }
     96 int main() {
     97     n = read(), m = read(), T = read();
     98     if (n != 1) work1::solve();
     99     else work2::solve(); 
    100     return 0;
    101 }
  • 相关阅读:
    基于DPDK的高效包处理系统
    Docker在centos系统上的安装
    TCP三次握手
    service与kube-proxy
    路由策略和策略路由
    golang context 超时自动取消方法
    用Dockerfile构建镜像
    kubemark模拟k8s计算节点,测试k8s组件性能
    golang动画等待计算菲波那契结果
    golang实现的倒计时计数器
  • 原文地址:https://www.cnblogs.com/mjtcn/p/9359145.html
Copyright © 2011-2022 走看看