zoukankan      html  css  js  c++  java
  • 纸箱堆叠 BZOJ 2253

    纸箱堆叠

    【问题描述】

    P 工厂是一个生产纸箱的工厂。纸箱生产线在人工输入三个参数 n, p, a 之后,即可自动化生产三边边长为

    (a mod P, a^2 mod p, a^3 mod P),(a^4 mod p, a^5 mod p, a^6 mod P),······,(a^(3n-2) mod p, a^(3n-1) mod p, a^(3n) mod p)

    的n个纸箱。在运输这些纸箱时,为了节约空间,必须将它们嵌套堆叠起来。

    一个纸箱可以嵌套堆叠进另一个纸箱当且仅当它的最短边、次短边和最长边长度分别严格小于另一个纸箱的最短边、次短边和最长边长度。这里不考虑任何旋转后在对角线方向的嵌套堆叠。

    你的任务是找出这n个纸箱中数量最多的一个子集,使得它们两两之间都可嵌套堆叠起来。

    【输入格式】

    输入文件的第一行三个整数,分别代表 a, p, n

    【输出格式】

    输出文件仅包含一个整数,代表数量最多的可嵌套堆叠起来的纸箱的个数。

    【样例输入】

     10 17 4

    【样例输出】

    2

    【样例说明】

    生产出的纸箱的三边长为(10, 15, 14), (4, 6, 9) , (5, 16, 7), (2, 3, 13)。其中只有(4, 6, 9)可堆叠进(5, 16, 7),故答案为 2。

    【样例说明】

    2<=P<=2000000000,1<=a<=p-1,a^k mod p<>0,ap<=2000000000,1<=N<=50000


    题解:

    我们设长宽高为x,y,z

    CDQ分治,以x为关键词排序

    接下来递归分成两区间

    假设左区间已经处理完了答案

    将左右区间分别以y为关键字排序

    那么就保证了任何左区间的x必定小于任何右区间的x

    我们用两个指针分别从左右区间顺序向后扫

    将左区间的z作为位置不断加入树状数组,值为当前点的答案

    由于左右区间有序,可以手动保证右区间的扫到的点的y大于所有左区间扫到的点的y

    就可以用树状数组更新右区间点的值:当前点的答案等于能转移到当前点的点的答案加一的最大值,这里用上了Dp的思想

    然后清空树状数组,再将左右区间合并按第一维排序,恢复原状态, 保证处理的是最初的右区间,且此区间按第一维有序

    接着递归处理右区间,继续更新答案

      1 #include<algorithm>
      2 #include<iostream>
      3 #include<cstdlib>
      4 #include<cstring>
      5 #include<cstdio>
      6 #include<cmath>
      7 using namespace std;
      8 inline int Get()
      9 {
     10     int x = 0;
     11     char c = getchar();
     12     while('0' > c || c > '9') c = getchar();
     13     while('0' <= c && c <= '9')
     14     {
     15         x = (x << 3) + (x << 1) + c - '0';
     16         c = getchar();
     17     }
     18     return x;
     19 }
     20 const int me = 100233;
     21 struct box
     22 {
     23     int x, y, z, ans;
     24 };
     25 box c[me], s[me];
     26 int a, p, n, m;
     27 int tr[me];
     28 int num[me];
     29 inline bool rulex(box a, box b)
     30 {
     31     if(a.x != b.x) return a.x < b.x;
     32     if(a.y != b.y) return a.y < b.y;
     33     return a.z < b.z;
     34 }
     35 inline bool rules(int a, int b)
     36 {
     37     if(s[a].z != s[b].z) return s[a].z < s[b].z;
     38     if(s[a].x != s[b].x) return s[a].x < s[b].x;
     39     return s[a].y < s[b].y;
     40 }
     41 inline bool ruley(box a, box b)
     42 {
     43     if(a.y != b.y) return a.y < b.y;
     44     return a.z < b.z;
     45 }
     46 inline int Max(int x)
     47 {
     48     int maxx = 0;
     49     while(x > 0)
     50     {
     51         maxx = max(tr[x], maxx);
     52         x -= x & (-x);
     53     }
     54     return maxx;
     55 }
     56 inline void Ins(int x, int y)
     57 {
     58     while(x <= m)
     59     {
     60         tr[x] = max(tr[x], y);
     61         x += x & (-x);
     62     }
     63 }
     64 inline void Del(int x)
     65 {
     66     while(x <= m)
     67     {
     68         tr[x] = 0;
     69         x += x & (-x);
     70     }
     71 }
     72 inline int Maxx(int x, int y)
     73 {
     74     return (x > y) ? x : y;
     75 }
     76 void Work(int l, int r)
     77 {
     78     if(l == r) return;
     79     int mi = l + r >> 1;
     80     while(s[mi].x == s[mi - 1].x) --mi;
     81     if(mi < l) return;
     82     Work(l, mi);
     83     sort(s + l, s + mi + 1, ruley);
     84     sort(s + mi + 1, s + r + 1, ruley);
     85     int u = l, v = mi + 1;
     86     while(u <= mi && v <= r)
     87     {
     88         if(s[u].y < s[v].y)
     89         {
     90             Ins(s[u].z, s[u].ans);
     91             ++u;
     92         }
     93         else
     94         {
     95             s[v].ans = Maxx(s[v].ans, Max(s[v].z - 1) + 1);
     96             ++v;
     97         }
     98     }
     99     for(int i = v; i <= r; ++i)
    100         s[i].ans = Maxx(s[i].ans, Max(s[i].z - 1) + 1);
    101     for(int i = l; i <= mi; ++i) Del(s[i].z);
    102     sort(s + mi + 1, s + r + 1, rulex);
    103     Work(mi + 1, r);
    104 }
    105 int cc[4];
    106 int main()
    107 {
    108     a = Get(), p = Get(), n = Get();
    109     cc[0] = 1;
    110     for(int i = 1; i <= n; ++i)
    111     {
    112         cc[1] = cc[0] * a % p;
    113         cc[2] = cc[1] * a % p;
    114         cc[3] = cc[2] * a % p;
    115         cc[0] = cc[3];
    116         sort(cc + 1, cc + 4);
    117         c[i].x = cc[1], c[i].y = cc[2], c[i].z = cc[3];
    118         c[i].ans = 1;
    119     }
    120     sort(c + 1, c + 1 + n, rulex);
    121     for(int i = 1; i <= n; ++i)
    122     {
    123         if(c[i].x != c[i - 1].x || c[i].y != c[i - 1].y || c[i].z != c[i - 1].z)
    124         {
    125             s[++m] = c[i];
    126             num[m] = m;
    127         }
    128     }
    129     sort(num + 1, num + 1 + m, rules);
    130     int k = 0;
    131     for(int i = 1; i <= m; ++i)
    132     {
    133         k = i;
    134         while(s[num[i]].z == s[num[i + 1]].z)
    135         {
    136             s[num[i]].z = k;
    137             ++i;
    138         }
    139         s[num[i]].z = k;
    140     }
    141     Work(1, m);
    142     int ans = 0;
    143     for(int i = 1; i <= m; ++i)
    144         if(s[i].ans > ans)
    145             ans = s[i].ans;
    146     printf("%d", ans);
    147 }
  • 相关阅读:
    深度神经网络的优化算法
    Python 正则表达式
    《java面试十八式》第一式 --冈本零点零一
    《java面试十八式》--引子
    Redis第二讲【Redis基本命令和五大数据结构】
    redis第一讲【redis的描述,linux和docker下的安装使用】
    springboot中的pom文件是如何管理依赖的
    详谈springboot启动类的@SpringBootApplication注解
    工具类中注入service和dao
    windows下安装ssdb
  • 原文地址:https://www.cnblogs.com/lytccc/p/6245668.html
Copyright © 2011-2022 走看看