【BZOJ2253】纸箱堆叠 [CDQ分治]

纸箱堆叠

Time Limit: 30 Sec  Memory Limit: 256 MB
[Submit][Status][Discuss]

Description

  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个纸箱中数量最多的一个子集,使得它们两两之间都可嵌套堆叠起来。

Input

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

Output

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

Sample Input

  10 17 4

Sample Output

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

HINT

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

Main idea

  每一个元素有三个属性a,b,c,求出最大可连续堆叠个数(可堆叠条件是a1<a2,b1<b2,c1<c2)

Solution

  题目显然是三维偏序问题,运用CDQ分治求解。

  用排序处理a保证a有序,分治的时候满足左区间的b都小于右区间的b,再处理c,这样问题就转化为了求一个点在一个平面上横纵坐标都小于它的点有几个,用树状数组处理即可。

  发现这样处理之后答案只能满足<=该点,考虑如何令答案严格小于

  首先b,c的严格小于处理显然,因为a是sort保证的那么如何要使得a的统计严格小于呢?只需要在b的sort前将分割的指针向左移动到第一个不等于的即可,结合分治考虑一下while(q[mid].a==q[mid-1].a) mid--,发现这样处理最后会影响到排序,所以做右区间的时候重新按照a排序一下即可。

  考虑如何统计答案,发现显然有: q[j].ans=max(q[j].ans,Query(q[j].c-1)+1)

Code

  1 #include<iostream>  
  2 #include<string>  
  3 #include<algorithm>  
  4 #include<cstdio>  
  5 #include<cstring>  
  6 #include<cstdlib>  
  7 #include<cmath>  
  8 using namespace std;  
  9    
 10 const int ONE=1000001;
 11  
 12 int n,MOD,a,m;
 13 int PD[4];
 14 int res;
 15 int C[ONE];
 16 int Ans,cnt;
 17  
 18 struct power
 19 {
 20         int a,b,c;
 21         int ans;
 22 }q[ONE];
 23  
 24 struct point
 25 {
 26         int pos,value;
 27 }Lisa[ONE];
 28  
 29 int get() 
 30 { 
 31         int res,Q=1;    char c;
 32         while( (c=getchar())<48 || c>57)
 33         if(c=='-')Q=-1;
 34         if(Q) res=c-48; 
 35         while((c=getchar())>=48 && c<=57) 
 36         res=res*10+c-48; 
 37         return res*Q; 
 38 }
 39  
 40 int cmp(const power &a,const power &b)
 41 {
 42         if(a.a!=b.a) return a.a<b.a;
 43         if(a.b!=b.b) return a.b<b.b;
 44         return a.c<b.c;
 45 }
 46  
 47 int cdp(const power &a,const power &b)
 48 {
 49         if(a.b!=b.b) return a.b<b.b;
 50         return a.c<b.c;
 51 }
 52  
 53 int rule(const power &a,const power &b)
 54 {
 55         return (a.a==b.a && a.b==b.b && a.c==b.c);
 56 }
 57  
 58 int lowbit(int x)
 59 {
 60         return x&-x;
 61 }
 62   
 63 int Add(int R,int x)
 64 {
 65         for(int i=R;i<=cnt;i+=lowbit(i))
 66         C[i]=max(C[i],x);
 67 }
 68   
 69 int Query(int R)
 70 {
 71         res=0;
 72         for(int i=R;i>=1;i-=lowbit(i))
 73         res=max(res,C[i]);
 74         return res;
 75 }
 76  
 77 int Clear(int R)
 78 {
 79         for(int i=R;i<=cnt;i+=lowbit(i))
 80         C[i]=0;
 81 }
 82  
 83 int clis(const point &a,const point &b)
 84 {
 85         return a.value<b.value;
 86 }
 87  
 88 void GetLisan()
 89 {
 90         sort(q+1,q+n+1,cmp);
 91         n=unique(q+1,q+n+1,rule)-1-q;
 92          
 93         for(int i=1;i<=n;i++)
 94         {
 95             Lisa[i].pos=i;
 96             Lisa[i].value=q[i].c;           
 97         }
 98         sort(Lisa+1,Lisa+n+1,clis);
 99          
100         cnt=0;
101         Lisa[0].value=-1;
102         for(int i=1;i<=n;i++)
103         {
104             if(Lisa[i].value!=Lisa[i-1].value) cnt++;
105             q[Lisa[i].pos].c=cnt;
106         }
107          
108 }
109  
110 void Deal(int l,int r)
111 {
112         if(l>=r) return;
113         int mid=(l+r)/2;
114         while(q[mid].a==q[mid-1].a) mid--;
115         if(mid<l) return;
116         Deal(l,mid);   
117         sort(q+l,q+mid+1,cdp);  sort(q+mid+1,q+r+1,cdp);
118          
119         int i=l,j=mid+1;
120         while(j<=r)
121         {
122             while(i<=mid && q[i].b<q[j].b)
123             {
124                 Add(q[i].c,q[i].ans);
125                 i++;    
126             }
127               
128             q[j].ans=max(q[j].ans,Query(q[j].c-1)+1);
129             j++;
130         }
131          
132   
133         for(int T=l;T<=mid;T++) 
134         { 
135             Clear(q[T].c);  
136         }
137         sort(q+mid+1,q+r+1,cmp);
138         Deal(mid+1,r);
139 }
140  
141 int main()
142 {      
143         a=get();    MOD=get();  n=get();
144         int j=0;    res=1;
145         for(int i=1;i<=n;i++)
146         {
147             for(int j=1;j<=3;j++)
148             {
149                 res=(long long)res*a%MOD;
150                 PD[j]=res;
151             }
152             sort(PD+1,PD+3+1);
153             q[i].a=PD[1]; q[i].b=PD[2]; q[i].c=PD[3];
154             q[i].ans=1;
155         }
156          
157         GetLisan();
158          
159         Deal(1,n);
160         for(int i=1;i<=n;i++)
161         Ans=max(Ans,q[i].ans);
162          
163         printf("%d",Ans);
164 }
View Code

 

转载于:https://www.cnblogs.com/BearChild/p/6426669.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
本火锅店点餐系统采用Java语言和Vue技术,框架采用SSM,搭配Mysql数据库,运行在Idea里,采用小程序模式。本火锅店点餐系统提供管理员、用户两种角色的服务。总的功能包括菜品的查询、菜品的购买、餐桌预定和订单管理。本系统可以帮助管理员更新菜品信息和管理订单信息,帮助用户实现在线的点餐方式,并可以实现餐桌预定。本系统采用成熟技术开发可以完成点餐管理的相关工作。 本系统的功能围绕用户、管理员两种权限设计。根据不同权限的不同需求设计出更符合用户要求的功能。本系统中管理员主要负责审核管理用户,发布分享新的菜品,审核用户的订餐信息和餐桌预定信息等,用户可以对需要的菜品进行购买、预定餐桌等。用户可以管理个人资料、查询菜品、在线点餐和预定餐桌、管理订单等,用户的个人资料是由管理员添加用户资料时产生,用户的订单内容由用户在购买菜品时产生,用户预定信息由用户在预定餐桌操作时产生。 本系统的功能设计为管理员、用户两部分。管理员为菜品管理、菜品分类管理、用户管理、订单管理等,用户的功能为查询菜品,在线点餐、预定餐桌、管理个人信息等。 管理员负责用户信息的删除和管理,用户的姓名和手机号都可以由管理员在此功能里看到。管理员可以对菜品的信息进行管理、审核。本功能可以实现菜品的定时更新和审核管理。本功能包括查询餐桌,也可以发布新的餐桌信息。管理员可以查询已预定的餐桌,并进行审核。管理员可以管理公告和系统的轮播图,可以安排活动。管理员可以对个人的资料进行修改和管理,管理员还可以在本功能里修改密码。管理员可以查询用户的订单,并完成菜品的安排。 当用户登录进系统后可以修改自己的资料,可以使自己信息的保持正确性。还可以修改密码。用户可以浏览所有的菜品,可以查看详细的菜品内容,也可以进行菜品的点餐。在本功能里用户可以进行点餐。用户可以浏览没有预定出去的餐桌,选择合适的餐桌可以进行预定。用户可以管理购物车里的菜品。用户可以管理自己的订单,在订单管理界面里也可以进行查询操作。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值