zoukankan      html  css  js  c++  java
  • [SDOI2010]粟粟的书架

    嘟嘟嘟


    哈,二合一题目。


    刚开始数据范围没看清,满脑子在想二维主席树。越想越觉得不可做。
    后来仔细的读了题,才发现这题前后50%的数据对应不同的做法。


    对于(R = 1)的数据,就是主席树板子。用主席树维护权值的后缀和,然后贪心往权值大的二分。
    需要注意的是相同权值的可能有多本书,要取大于等于(h)的最少数量。


    对于剩下50%。令f[i][j][k]表示((1, 1))((i, j))的前缀矩阵中,权值大于等于(k)的书的高度之和;g[i][j][k]表示对应的数量之和。
    然后二分,如果当前的和小于(h),就令L = mid - 1;否则R = mid。
    同样需要注意的是相同高度的书可能有多个。还是要取大于(h)最少的书。

    #include<cstdio>
    #include<iostream>
    #include<cmath>
    #include<algorithm>
    #include<cstring>
    #include<cstdlib>
    #include<cctype>
    #include<vector>
    #include<stack>
    #include<queue>
    using namespace std;
    #define enter puts("") 
    #define space putchar(' ')
    #define Mem(a, x) memset(a, x, sizeof(a))
    #define In inline
    typedef long long ll;
    typedef double db;
    const int INF = 0x3f3f3f3f;
    const db eps = 1e-8;
    const int maxn1 = 205;
    const int maxn2 = 5e5 + 5;
    const int maxN = 1e3 + 5;
    inline ll read()
    {
      ll ans = 0;
      char ch = getchar(), last = ' ';
      while(!isdigit(ch)) last = ch, ch = getchar();
      while(isdigit(ch)) ans = (ans << 1) + (ans << 3) + ch - '0', ch = getchar();
      if(last == '-') ans = -ans;
      return ans;
    }
    inline void write(ll x)
    {
      if(x < 0) x = -x, putchar('-');
      if(x >= 10) write(x / 10);
      putchar(x % 10 + '0');
    }
    
    int n, m, q;
    
    int a[maxn1][maxn1], Max = 0;
    ll f[maxn1][maxn1][maxN];
    int g[maxn1][maxn1][maxN];
    In int solve(int xa, int ya, int xb, int yb, ll h)
    {
      int L = 0, R = Max, ret = 0;
      while(L < R)
        {
          int mid = (L + R + 1) >> 1;
          ll Sum = f[xb][yb][mid] - f[xb][ya - 1][mid] - f[xa - 1][yb][mid] + f[xa - 1][ya - 1][mid];
          if(Sum < h) R = mid - 1;
          else L = mid;
        }
      if(L == 0) return -1;
      ret = g[xb][yb][L + 1] - g[xb][ya - 1][L + 1] - g[xa - 1][yb][L + 1] + g[xa - 1][ya - 1][L + 1];
      h -= f[xb][yb][L + 1] - f[xb][ya - 1][L + 1] - f[xa - 1][yb][L + 1] + f[xa - 1][ya - 1][L + 1];
      ll Sum = (f[xb][yb][L] - f[xb][ya - 1][L] - f[xa - 1][yb][L] + f[xa - 1][ya - 1][L]) - (f[xb][yb][L + 1] - f[xb][ya - 1][L + 1] - f[xa - 1][yb][L + 1] + f[xa - 1][ya - 1][L + 1]);
      int num = (g[xb][yb][L] - g[xb][ya - 1][L] - g[xa - 1][yb][L] + g[xa - 1][ya - 1][L]) - (g[xb][yb][L + 1] - g[xb][ya - 1][L + 1] - g[xa - 1][yb][L + 1] + g[xa - 1][ya - 1][L + 1]);
      ll pri = Sum / num;
      return ret + (h + pri - 1) / pri;
    }
    In void work0()
    {
      for(int i = 1; i <= n; ++i)
        for(int j = 1; j <= m; ++j) a[i][j] = read(), Max = max(Max, a[i][j]);
      for(int i = 1; i <= n; ++i)
        for(int j = 1; j <= m; ++j)
          {
    	  for(int k = 0; k <= Max; ++k)
    	  {
    	    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 k = 0; k <= a[i][j]; ++k) f[i][j][k] += a[i][j], ++g[i][j][k];
          }
      for(int i = 1; i <= q; ++i)
        {
          int xa = read(), ya = read(), xb = read(), yb = read();
          ll h = read();
          int ans = solve(xa, ya, xb, yb, h);
          if(ans < 0) puts("Poor QLW");
          else write(ans), enter;
        }
    }
    
    struct Tree
    {
      int ls, rs;
      int num; ll sum;
    }t[maxn2 * 20];
    int root[maxn2], tcnt = 0;
    
    In void insert(int old, int& now, int l, int r, int id)
    {
      t[now = ++tcnt] = t[old];
      t[now].sum += id; ++t[now].num;
      if(l == r) return;
      int mid = (l + r) >> 1;
      if(id <= mid) insert(t[old].ls, t[now].ls, l, mid, id);
      else insert(t[old].rs, t[now].rs, mid + 1, r, id);
    }
    In int query(int old, int now, int l, int r, ll h)
    {
      if(!now && h) return -INF;
      if(l == r)
        {
          ll Sum = t[now].sum - t[old].sum, pri = Sum / (t[now].num - t[old].num);
          if(Sum < h) return -INF;
          else return (h + pri - 1) / pri;
        }
      int mid = (l + r) >> 1;
      ll Sum = t[t[now].rs].sum - t[t[old].rs].sum;
      if(Sum > h) return query(t[old].rs, t[now].rs, mid + 1, r, h);
      else if(Sum == h) return t[t[now].rs].num - t[t[old].rs].num;
      else return t[t[now].rs].num - t[t[old].rs].num + query(t[old].ls, t[now].ls, l, mid, h - Sum);
    }
      
    int main()
    {
      n = read(), m = read(), q = read();
      if(n ^ 1) {work0(); return 0;}
      for(int i = 1, x; i <= m; ++i) x = read(), insert(root[i - 1], root[i], 0, maxN - 5, x);
      for(int i = 1, L, R; i <= q; ++i)
        {
          read(), L = read(), read(), R = read();
          ll h = read();
          int ans = query(root[L - 1], root[R], 0, maxN - 5, h);
          if(ans < 0) puts("Poor QLW");
          else write(ans), enter;
        }
      return 0;
    }
    
  • 相关阅读:
    Nginx.conf 配置文件详细说明
    CentOs中iptables配置允许mysql远程访问
    CentOS 6.4下编译安装MySQL 5.6.14
    CentOS6.4下Mysql数据库的安装与配置
    让nginx支持.htaccess文件实现伪静态的方法!
    MySQL导入.sql文件及常用命令
    PHP里10个鲜为人知但却非常有用的函数
    Nginx配置文件详细说明
    linux 开机启动nginx
    Redhat系列使用ISO或者光盘制作yum本地安装源
  • 原文地址:https://www.cnblogs.com/mrclr/p/10392165.html
Copyright © 2011-2022 走看看