很好的题,值得细细说,(果然又是个假期望).......
首先我们提取信息,显然这是个三维偏序问题
用简单的DP式子表示需要满足
f[i]=max(f[1--j]+1)(v[j]<v[i],h[j]<h[i],j<i)
那么我们发现这样可以愉快的CDQ,方案数用g数组表示,
在树状数组中注意维护就好
void add(int x,int kx,double kxx) { for(int i=x;i<=h_tot;i+=lowbit(i)) { if(kx==c[i]) { c2[i]+=kxx; } else if(kx>c[i]) { c2[i]=kxx;c[i]=kx; } } }
(注意这里+的方案数,是当前增加的值的方案数)
这样就结束了????
在这里才发现了CDQ优化DP的方法有些不同
我们发现普通的CDQ是将子区间处理完后,才会处理更大的区间
然而这里有一些不同的是,我们并不能一个一个小区间的处理
例如一串数 1 2 3 4 5 6
如果我们先处理左区间1-3在处理右区间4-6,在处理最后
我们发现可能的结果是1-3先更新4,5,
然后4,5更新6,显然这样是满足DP规律的
我们不妨将其看作中序遍历,先左后中后右,这样保证了正确性QAQ
注意:
这样就不能像原来一样保证序列的有序,这样我们牺牲时间
每次处理新区间时,将左右两区间按第二关键字排序一遍
然后处理完后早将这个的大区间按第一关键字排回,这样保证有序
(原来区间从下向上第一关键字当然有序,这时先大区间后小区间就要重新排了)
还有我们要两次扫,因为假设是1-n搜表示以i结尾的最大不上升序列长度
然而我们的i可能卡在中间,那么我们把区间倒转,再将每个a[i]变值(原来小的变成大的),然后只要打一遍CDQ就好了
1 #include<iostream> 2 #include<cstdio> 3 #include<string> 4 #include<algorithm> 5 #include<cmath> 6 #include<vector> 7 #include<map> 8 #include<cstring> 9 #define MAXN 510001 10 #define int long long 11 using namespace std; 12 struct node{int v,h,id;}e[MAXN]; 13 int lowbit(int x){return x&(-x);} 14 bool cmp(const node &a,const node &b) {return a.id<b.id;} 15 int h_tot,v_tot; 16 int c[MAXN]; 17 double c2[MAXN]; 18 int dp[MAXN][3]; 19 double g[MAXN][3]; 20 int v_old[MAXN],h_old[MAXN]; 21 int n;int maxn=0; 22 double geshu=0.0; 23 double ans[MAXN]; 24 void add(int x,int kx,double kxx) 25 { 26 for(int i=x;i<=h_tot;i+=lowbit(i)) 27 { 28 if(kx==c[i]) 29 { 30 c2[i]+=kxx; 31 } 32 else if(kx>c[i]) 33 { 34 c2[i]=kxx;c[i]=kx; 35 } 36 } 37 } 38 int query(int x) 39 { 40 int anss=0; 41 for(int i=x;i>=1;i-=lowbit(i)) 42 { 43 if(c[i]>anss) 44 { 45 geshu=c2[i];anss=c[i]; 46 } 47 else if(c[i]==anss) 48 { 49 geshu+=c2[i]; 50 } 51 } 52 return anss; 53 } 54 void clear(int x) 55 { 56 for(int i=x;i<=h_tot;i+=lowbit(i)){c[i]=0;c2[i]=0.0;} 57 } 58 bool cmp_v(const node &a,const node &b) 59 { 60 return (a.v==b.v)?((a.h==b.h)?(a.id<b.id):a.h<b.h):(a.v<b.v); 61 } 62 void work1(int l,int r,int mid,int me) 63 { 64 sort(e+l,e+r+1,cmp_v); 65 for(int i=l;i<=r;++i) 66 { 67 if(e[i].id<=mid) 68 { 69 add(e[i].h,dp[e[i].id][me],g[e[i].id][me]); 70 } 71 else 72 { 73 geshu=0; 74 int ttt=query(e[i].h)+1; 75 if(ttt>dp[e[i].id][me]) 76 { 77 dp[e[i].id][me]=ttt; 78 g[e[i].id][me]=geshu; 79 } 80 else if(ttt==dp[e[i].id][me]) 81 { 82 g[e[i].id][me]+=geshu; 83 } 84 } 85 } 86 for(int i=l;i<=r;++i) 87 { 88 if(e[i].id<=mid) 89 clear(e[i].h); 90 } 91 sort(e+l,e+r+1,cmp); 92 } 93 void solve(int l,int r,int me) 94 { 95 int mid=(l+r)>>1; 96 if(l==r)return ; 97 solve(l,mid,me); 98 work1(l,r,mid,me); 99 solve(mid+1,r,me); 100 return ; 101 } 102 signed main() 103 { 104 scanf("%lld",&n); 105 for(int i=1;i<=n;++i) 106 { 107 scanf("%lld%lld",&h_old[n-i+1],&v_old[n-i+1]); 108 e[n-i+1].h=h_old[n-i+1]; 109 e[n-i+1].v=v_old[n-i+1]; 110 e[n-i+1].id=n-i+1; 111 } 112 sort(h_old+1,h_old+n+1); 113 sort(v_old+1,v_old+n+1); 114 h_tot=unique(h_old+1,h_old+n+1)-h_old-1; 115 v_tot=unique(v_old+1,v_old+n+1)-v_old-1; 116 for(int i=1;i<=n;++i) 117 { 118 e[i].h=lower_bound(h_old+1,h_old+h_tot+1,e[i].h)-h_old; 119 e[i].v=lower_bound(v_old+1,v_old+v_tot+1,e[i].v)-v_old; 120 } 121 for(int i=1;i<=n;++i) 122 { 123 dp[e[i].id][1]=1;dp[e[i].id][2]=1; 124 g[e[i].id][1]=1;g[e[i].id][2]=1; 125 } 126 sort(e+1,e+n+1,cmp); 127 solve(1,n,1); 128 /*for(int i=1;i<=n;++i) 129 { 130 printf("dp[%lld][1]=%lld g[%lld][1]=%lld ",i,dp[i][1],i,g[i][1]); 131 }*/ 132 for(int i=1;i<=n;++i) 133 maxn=max(maxn,dp[i][1]); 134 reverse(e+1,e+n+1); 135 for(int i=1;i<=n;++i) 136 { 137 e[i].h=h_tot-e[i].h+1; 138 e[i].v=v_tot-e[i].v+1; 139 e[i].id=i; 140 } 141 solve(1,n,2); 142 double sum=0.0; 143 for(int i=1;i<=n;++i) 144 { 145 if(dp[i][1]==maxn)sum+=g[i][1]; 146 } 147 for(int i=1;i<=n;++i) 148 { 149 if(dp[n-i+1][2]+dp[i][1]-1==maxn) 150 { 151 ans[i]=(g[i][1]*g[n-i+1][2])/sum; 152 //printf("ans[%lld]=%.4lf ",i,ans[i]); 153 } 154 else ans[i]=0.0; 155 } 156 printf("%lld ",maxn); 157 for(int i=n;i>=1;--i) 158 { 159 printf("%.5lf ",ans[i]); 160 } 161 cout<<endl; 162 }