您的位置:首页 > 其它

bzoj 2253: [2010 Beijing wc]纸箱堆叠 (CDQ分治+DP)

2017-03-24 20:18 316 查看

题目描述

传送门

题目大意:每个物品有三个参数(x,y,z),一个物品只有三个参数同时严格小于另一个物品,才能放到另一个物品中。问最多多少个两两嵌套。

题解

我们先按照x坐标排好序,然后进行CDQ分治。

分治的时候先计算[l,mid]的中点的答案。

然后按照y排序,将原本[l,mid]中的点一次加入他们z值对应的树状数组中。

[r,mid]中的点从树状数组中查询小于z的区间最小值,更新答案。

代码

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#define N 50003
#define LL long long
using namespace std;
int f[N*3],n,base,p,tr[N*3],mul[N*3],b[N*3],cnt,ll[N*3],rr[N*3],c[N*3];
bool mark
;
struct data{
int x,y,z,id,pd;
}a
;
int cmp(data a,data b)
{
return a.x<b.x;
}
int cmp1(data a,data b)
{
return  a.y<b.y||a.y==b.y&&a.x<b.x;
}
int lowbit(int x){
return x&(-x);
}
void change(int x,int val)
{
for (int i=x;i<=cnt;i+=lowbit(i))
tr[i]=max(tr[i],val);
}
int query(int x)
{
int ans=0;
if (!x) return 0;
for (int i=x;i>=1;i-=lowbit(i))
ans=max(ans,tr[i]);
return ans;
}
void clear(int x)
{
for (int i=x;i<=cnt;i+=lowbit(i)) tr[i]=0;
}
void divide(int l,int r)
{
if (l>=r) return;
sort(a+l,a+r+1,cmp);
//cout<<l<<" "<<r<<endl;
//for (int i=l;i<=r;i++) cout<<a[i].x<<" "<<a[i].y<<" "<<a[i].z<<" "<<a[i].id<<endl;
int mid=(l+r)/2;
int L=ll[l]; int R=rr[r];
divide(l,mid);
for (int i=L;i<=rr[mid];i++) a[i].pd=1;
for (int i=rr[mid]+1;i<=R;i++) a[i].pd=0;
sort(a+L,a+R+1,cmp1); int j;
for (int i=L;i<=R;i=j+1) {
j=i;
while (j<R&&a[i].y==a[j+1].y) j++;
for (int k=i;k<=j;k++)
if (a[k].pd==0) {
int t=a[k].id;
f[t]=max(f[t],query(a[k].z-1)+1);
}
for (int k=i;k<=j;k++)
if (a[k].pd==1) change(a[k].z,f[a[k].id]);
}
for (int i=L;i<=R;i++)
if (a[i].pd==1) clear(a[i].z);
sort(a+L,a+R+1,cmp);
divide(mid+1,r);
}
int main()
{
freopen("a.in","r",stdin);
freopen("my.out","w",stdout);
scanf("%d%d%d",&base,&p,&n);
mul[0]=1; int t=0;
for (int i=1;i<=3*n;i++) mul[i]=(LL)mul[i-1]*base%p,b[i]=mul[i];
sort(b+1,b+3*n+1);
cnt=unique(b+1,b+3*n+1)-b-1;
for (int i=1;i<=n;i++){
int t1=(i-1)*3; a[i].id=i;
//cout<<mul[t+1]<<" "<<mul[t+2]<<" "<<mul[t+3]<<endl;
a[i].x=lower_bound(b+1,b+cnt+1,mul[t1+1])-b;
a[i].y=lower_bound(b+1,b+cnt+1,mul[t1+2])-b;
a[i].z=lower_bound(b+1,b+cnt+1,mul[t1+3])-b;
if (a[i].y<a[i].x) swap(a[i].x,a[i].y);
if (a[i].z<a[i].x) swap(a[i].x,a[i].z);
if (a[i].z<a[i].y) swap(a[i].z,a[i].y);
//cout<<a[i].x<<" "<<a[i].y<<" "<<a[i].z<<endl;
c[++t]=a[i].x;
}
sort(c+1,c+t+1);
t=unique(c+1,c+t+1)-c-1;
// cout<<t<<endl;
for (int i=1;i<=n;i++) a[i].x=lower_bound(c+1,c+t+1,a[i].x)-c;
for (int i=1;i<=n;i++)  f[i]=1;
sort(a+1,a+n+1,cmp);
a[n+1].x=1000000000;
for (int i=1;i<=n;i++) {
//cout<<a[i].x<<endl;
if (a[i-1].x<a[i].x) ll[a[i].x]=i;
if (a[i+1].x>a[i].x) rr[a[i].x]=i;
}
divide(1,t);
int ans=0;
for (int i=1;i<=n;i++) ans=max(ans,f[i]);
printf("%d\n",ans);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  dp CDQ分治