题目大意:给定一个序列,每个元素是一个二元组,等概率选择一LIS,求LIS长度以及每个元素被选中的概率
第一问CDQ分治裸上
第二问用每个元素所在的LIS个数/总LIS个数就是答案
每个元素所在的LIS自己必选,然后统计前面的方案数和后面的方案数
以前面的方案数为例,令f[x]为以x结尾的LIS长度,那么有DP方程:
g[i]=Σg[j] (f[j]+1=f[i],j<i,a[j].x<a[i].x,a[j].y<a[i].y)
将所有元素按f值排序,分层DP,每层DP是一个三维偏序,上CDQ分治再搞搞就好了
(我偷懒写了二维树状数组QAQ)
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define M 50500
using namespace std;
typedef double ld;
int n,ans,tot;
int f[M];
ld g[M],h[M],total;
struct abcd{
int x,y;
}*a[M],*_a[M],mempool[M];
bool Compare(abcd *a1,abcd *a2)
{
if( a1->x != a2->x )
return a1->x < a2->x ;
return a1->y < a2->y ;
}
bool _Compare(int x,int y)
{
if( f[x] != f[y] )
return f[x] < f[y] ;
return x < y ;
}
void Discretization()
{
static pair<int,int*> b[M];
int i;
for(i=1;i<=n;i++)
b[i]=make_pair(-a[i]->x,&a[i]->x);
sort(b+1,b+n+1);
for(tot=0,i=1;i<=n;i++)
{
if(i==1||b[i].first!=b[i-1].first)
++tot;
*b[i].second=tot;
}
for(i=1;i<=n;i++)
b[i]=make_pair(-a[i]->y,&a[i]->y);
sort(b+1,b+n+1);
for(tot=0,i=1;i<=n;i++)
{
if(i==1||b[i].first!=b[i-1].first)
++tot;
*b[i].second=tot;
}
}
namespace BIT{
int c[M],tim[M],T;
void Initialize()
{
++T;
}
void Update(int x,int y)
{
for(;x<=n;x+=x&-x)
{
if(tim[x]!=T)
tim[x]=T,c[x]=0;
c[x]=max(c[x],y);
}
}
int Get_Ans(int x)
{
int re=0;
for(;x;x-=x&-x)
if(tim[x]==T)
re=max(re,c[x]);
return re;
}
}
void CDQ_Divide_And_Conquer(int l,int r)
{
using namespace BIT;
int i,j,mid=l+r>>1;
if(l==r)
{
f[mid]++;
ans=max(ans,f[mid]);
return ;
}
int l1=l,l2=mid+1;
for(i=l;i<=r;i++)
if(a[i]-mempool<=mid)
_a[l1++]=a[i];
else
_a[l2++]=a[i];
memcpy(a+l,_a+l,sizeof(a[0])*(r-l+1));
CDQ_Divide_And_Conquer(l,mid);
Initialize();
for(j=l,i=mid+1;i<=r;i++)
{
for(;j<=mid&&a[j]->x<=a[i]->x;j++)
Update(a[j]->y,f[a[j]-mempool]);
f[a[i]-mempool]=max(f[a[i]-mempool],Get_Ans(a[i]->y));
}
CDQ_Divide_And_Conquer(mid+1,r);
l1=l;l2=mid+1;
for(i=l;i<=r;i++)
if( l2>r || l1<=mid && Compare(a[l1],a[l2]) )
_a[i]=a[l1++];
else
_a[i]=a[l2++];
memcpy(a+l,_a+l,sizeof(a[0])*(r-l+1));
}
namespace Bidimensional_BIT{
namespace Hash_Table{
struct List{
int x,y;
ld val;
List *next;
List() {}
List(int _,int __,List *___):
x(_),y(__),val(0),next(___) {}
}mempool[12000000],*C=mempool,*head[1031][1301];
int tim[1031][1301],T;
void Initialize()
{
C=mempool;
++T;
}
ld& Hash(int x,int y)
{
int pos1=x%1031,pos2=y%1301;
List *temp;
if(tim[pos1][pos2]!=T)
tim[pos1][pos2]=T,head[pos1][pos2]=0;
for(temp=head[pos1][pos2];temp;temp=temp->next)
if(temp->x==x&&temp->y==y)
return temp->val;
return (head[pos1][pos2]=new List(x,y,head[pos1][pos2]))->val;
}
ld Get_Hash(int x,int y)
{
int pos1=x%1031,pos2=y%1301;
List *temp;
if(tim[pos1][pos2]!=T)
tim[pos1][pos2]=T,head[pos1][pos2]=0;
for(temp=head[pos1][pos2];temp;temp=temp->next)
if(temp->x==x&&temp->y==y)
return temp->val;
return 0;
}
}
using namespace Hash_Table;
void Update(int x,int y,ld val,int flag)
{
int i,j;
for(i=x;i&&i<=n;i+=flag*(i&-i))
for(j=y;j&&j<=n;j+=flag*(j&-j))
Hash(i,j)+=val;
}
ld Get_Ans(int x,int y,int flag)
{
ld re=0;
int i,j;
for(i=x;i&&i<=n;i+=flag*(i&-i))
for(j=y;j&&j<=n;j+=flag*(j&-j))
re+=Get_Hash(i,j);
return re;
}
}
int main()
{
//freopen("3756.in","r",stdin);
//freopen("3756.out","w",stdout);
int i,j;
cin>>n;
for(i=1;i<=n;i++)
{
scanf("%d%d",&mempool[i].x,&mempool[i].y);
a[i]=&mempool[i];
}
Discretization();
sort(a+1,a+n+1,Compare);
CDQ_Divide_And_Conquer(1,n);
cout<<ans<<endl;
static int a[M];
for(i=1;i<=n;i++)
a[i]=i;
sort(a+1,a+n+1,_Compare);
for(i=1;i<=n&&f[a[i]]==1;i++)
g[a[i]]=1;
for(j=1;i<=n;i++)
{
if(f[a[i]]!=f[a[i-1]])
{
for(;f[a[j]]+1!=f[a[i]];j++);
Bidimensional_BIT::Initialize();
}
for(;a[j]<a[i]&&f[a[j]]==f[a[i]]-1;j++)
Bidimensional_BIT::Update(mempool[a[j]].x,mempool[a[j]].y,g[a[j]],1);
g[a[i]]=Bidimensional_BIT::Get_Ans(mempool[a[i]].x,mempool[a[i]].y,-1);
}
for(i=n;i&&f[a[i]]==ans;i--)
h[a[i]]=1;
for(j=n;i;i--)
{
if(f[a[i]]!=f[a[i+1]])
{
for(;f[a[j]]-1!=f[a[i]];j--);
Bidimensional_BIT::Initialize();
}
for(;a[j]>a[i]&&f[a[j]]==f[a[i]]+1;j--)
Bidimensional_BIT::Update(mempool[a[j]].x,mempool[a[j]].y,h[a[j]],-1);
h[a[i]]=Bidimensional_BIT::Get_Ans(mempool[a[i]].x,mempool[a[i]].y,1);
}
for(i=1;i<=n&&f[a[i]]==1;i++)
total+=h[a[i]];
for(i=1;i<=n;i++)
printf("%.10lf%c",(double)(g[i]*h[i]/total),i==n?'\n':' ');
return 0;
}