您的位置:首页 > 其它

BZOJ 2253 纸箱堆叠(CDQ分治)

2016-04-07 10:06 351 查看
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

Solution

三维LIS问题,CDQ分治,按第一维x排序,由于此处是严格上升,故在分治过程中mid值需要使得[l,,mid]的第一维严格小于[mid+1,r]的第一维,以dp[i]表示以第i个元素结尾的LIS长度,则有dp[i]=max(dp[i],dp[j]+1),其中mid+1<=i<=r,l<=j<=mid,yj < yi,zj < zi,如果对[l,mid]和[mid+1,r]都按y为第一关键字,z为第二关键字升序排,每次计算dp[i]之前将所有满足yj < yi的j都以zj为下标,dp[j]为键值插入到树状数组中,那么问题转化为求树状数组中下标小于zi的最大值,最后的答案为max(dp[i])

Code

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
#define maxn 111111
int A,P,n,t[maxn],tot;
struct node
{
int x,y,z,ans;
void init(int a,int b,int c)
{
if(a>b)swap(a,b);
if(a>c)swap(a,c);
if(b>c)swap(b,c);
x=a,y=b,t[++tot]=z=c,ans=1;
}
}p[maxn];
int cmpx(node a,node b)
{
if(a.x!=b.x)return a.x<b.x;
if(a.y!=b.y)return a.y<b.y;
return a.z<b.z;
}
int cmpy(node a,node b)
{
if(a.y!=b.y)return a.y<b.y;
return a.z<b.z;
}
struct BIT
{
#define lowbit(x) (x&(-x))
int b[maxn];
void init()
{
memset(b,0,sizeof(b));
}
void update(int x,int v)
{
while(x<=n)
{
b[x]=max(b[x],v);
x+=lowbit(x);
}
}
int query(int x)
{
int ans=0;
while(x)
{
ans=max(ans,b[x]);
x-=lowbit(x);
}
return ans;
}
void clear(int x)
{
while(x<=n)
{
b[x]=0;
x+=lowbit(x);
}
}
}bit;
void CDQ(int l,int r)
{
if(l>=r)return ;
//保证[l,mid]的第一维严格小于[mid+1,r]的第一维
int mid=-1,tl=(l+r)>>1,tr=tl+1;
while(tl>=l||tr<=r)
{
if(tl>=l&&p[tl].x!=p[tl+1].x)
{
mid=tl;
break;
}
if(tr<=r&&p[tr-1].x!=p.x)
{
mid=tr-1;
break;
}
tl--,tr++;
}
if(mid==-1)return ;
CDQ(l,mid);
sort(p+l,p+mid+1,cmpy);
sort(p+mid+1,p+r+1,cmpy);
for(int i=mid+1,j=l;i<=r;i++)
{
for(;j<=mid&&p[j].y<p[i].y;j++)
bit.update(p[j].z,p[j].ans);
p[i].ans=max(p[i].ans,bit.query(p[i].z-1)+1);
}
for(int i=l;i<=mid;i++)bit.clear(p[i].z);
sort(p+mid+1,p+r+1,cmpx);
CDQ(mid+1,r);
}
int main()
{
scanf("%d%d%d",&A,&P,&n);
tot=0,bit.init();
int x,y,z,temp=1;
for(int i=1;i<=n;i++)
{
x=temp=1ll*A*temp%P;
y=temp=1ll*A*temp%P;
z=temp=1ll*A*temp%P;
p[i].init(x,y,z);
}
sort(p+1,p+n+1,cmpx);
sort(t+1,t+tot+1);
for(int i=1;i<=n;i++)
p[i].z=lower_bound(t+1,t+tot+1,p[i].z)-t;
CDQ(1,n);
int ans=1;
for(int i=1;i<=n;i++)ans=max(ans,p[i].ans);
printf("%d\n",ans);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: