bzoj2244 [SDOI2011]拦截导弹

传送门

这题其实没那么难,只是我做法麻烦所以调起来相当费事儿……这人没救了

第一问显然是裸的三维偏序,分治随便搞搞就行了。考虑第二问,答案其实就是包括它的子序列数除以总方案数,那么定义$g[i]$为以i结尾的子序列数量,$h[i]$为以i开头的子序列数量,包括它的子序列数就是$g[i]h[i]$了。

而$g[i],h[i]$的转移方程分别是:

\begin{align}g[i]=\sum_{j<i,a_j<a_i,f[j]=f[i]-1}g[j]\end{align}

\begin{align}g[i]=1(f[i]=1)\end{align}

\begin{align}h[i]=\sum_{i<j,a_i<a_j,f[i]=f[j]-1}h[j]\end{align}

\begin{align}h[i]=1(f[i]=\max_{j=1}^n{f[j]})\end{align}

(注:这里的$<$都是指满足题中的偏序关系)

不难看出这还是三维偏序的形式,再跑两遍分治即可。

三遍分治都是手打的,没有用复制粘贴,写了好久……超过200行的分治,真是醉了……

  1 /**************************************************************
  2     Problem: 2244
  3     User: hzoier
  4     Language: C++
  5     Result: Accepted
  6     Time:4636 ms
  7     Memory:6368 kb
  8 ****************************************************************/
  9 #include<cstdio>
 10 #include<cstring>
 11 #include<algorithm>
 12 #include<vector>
 13 using namespace std;
 14 const int maxn=50010;
 15 struct A{
 16     int x,y,id;
 17     bool ins;
 18     bool operator<(const A &a)const{
 19         if(x!=a.x)return x<a.x;
 20         return ins&&!a.ins;
 21     }
 22 }a[maxn],aa[maxn],b[maxn];
 23 bool cmp(const A &a,const A &b){
 24     if(a.x!=b.x)return a.x>b.x;
 25     return a.ins&&!b.ins;
 26 }
 27 void CDQ1(int,int);
 28 void CDQ2(int,int);
 29 void CDQ3(int,int);
 30 void add1(int,int);
 31 void add2(int,long double);
 32 int query1(int);
 33 long double query2(int);
 34 void clear1(int);
 35 void clear2(int);
 36 vector<int>vec[maxn];
 37 long double c2[maxn]={0},g[maxn]={0},h[maxn]={0},tmp=0.0;
 38 int n,t[maxn],f[maxn],c1[maxn],ans;
 39 int main(){
 40     scanf("%d",&n);
 41     for(int i=1;i<=n;i++){
 42         scanf("%d%d",&a[i].x,&a[i].y);
 43         t[i]=a[i].y;
 44         a[i].id=i;
 45         f[i]=1;
 46     }
 47     sort(t+1,t+n+1);
 48     for(int i=1;i<=n;i++)a[i].y=lower_bound(t+1,t+n+1,a[i].y)-t;
 49     copy(a+1,a+n+1,aa+1);
 50     CDQ1(1,n);
 51     for(int i=1;i<=n;i++){
 52         ans=max(ans,f[i]);
 53         vec[f[i]].push_back(i);
 54     }
 55     printf("%d\n",ans);
 56     for(int i=0;i<(int)vec[1].size();i++)g[vec[1][i]]=1.0;
 57     for(int k=2;k<=ans;k++){
 58         int i=0,j=0,cnt=0;
 59         while(i<(int)vec[k-1].size()&&j<(int)vec[k].size()){
 60             if(vec[k-1][i]<vec[k][j]){
 61                 b[++cnt]=aa[vec[k-1][i]];
 62                 b[cnt].ins=true;
 63                 i++;
 64             }
 65             else{
 66                 b[++cnt]=aa[vec[k][j]];
 67                 b[cnt].ins=false;
 68                 j++;
 69             }
 70         }
 71         while(i<(int)vec[k-1].size()){
 72             b[++cnt]=aa[vec[k-1][i]];
 73             b[cnt].ins=true;
 74             i++;
 75         }
 76         while(j<(int)vec[k].size()){
 77             b[++cnt]=aa[vec[k][j]];
 78             b[cnt].ins=false;
 79             j++;
 80         }
 81         CDQ2(1,cnt);
 82     }
 83     for(int i=0;i<(int)vec[ans].size();i++){
 84         tmp+=g[vec[ans][i]];
 85         h[vec[ans][i]]=1.0;
 86     }
 87     for(int k=ans-1;k;k--){
 88         int i=0,j=0,cnt=0;
 89         while(i<(int)vec[k+1].size()&&j<(int)vec[k].size()){
 90             if(vec[k+1][i]<vec[k][j]){
 91                 b[++cnt]=aa[vec[k+1][i]];
 92                 b[cnt].ins=true;
 93                 i++;
 94             }
 95             else{
 96                 b[++cnt]=aa[vec[k][j]];
 97                 b[cnt].ins=false;
 98                 j++;
 99             }
100         }
101         while(i<(int)vec[k+1].size()){
102             b[++cnt]=aa[vec[k+1][i]];
103             b[cnt].ins=true;
104             i++;
105         }
106         while(j<(int)vec[k].size()){
107             b[++cnt]=aa[vec[k][j]];
108             b[cnt].ins=false;
109             j++;
110         }
111         CDQ3(1,cnt);
112     }
113     for(int i=1;i<=n;i++)printf("%.10lf ",(double)(g[i]*h[i]/tmp));
114     return 0;
115 }
116 void CDQ1(int l,int r){
117     if(l>=r)return;
118     int mid=(l+r)>>1;
119     CDQ1(l,mid);
120     copy(aa+l,aa+r+1,a+l);
121     sort(a+l,a+mid+1,cmp);
122     sort(a+mid+1,a+r+1,cmp);
123     int i=l,j=mid+1;
124     while(i<=mid&&j<=r){
125         if(a[i].x>=a[j].x){
126             add1(n-a[i].y+1,f[a[i].id]);
127             i++;
128         }
129         else{
130             f[a[j].id]=max(f[a[j].id],query1(n-a[j].y+1)+1);
131             j++;
132         }
133     }
134     while(j<=r){
135         f[a[j].id]=max(f[a[j].id],query1(n-a[j].y+1)+1);
136         j++;
137     }
138     for(i=l;i<=mid;i++)clear1(n-a[i].y+1);
139     CDQ1(mid+1,r);
140 }
141 void CDQ2(int l,int r){
142     if(l>=r)return;
143     int mid=(l+r)>>1;
144     CDQ2(l,mid);
145     copy(b+l,b+r+1,a+l);
146     sort(a+l,a+mid+1,cmp);
147     sort(a+mid+1,a+r+1,cmp);
148     int i=l,j=mid+1;
149     while(i<=mid&&j<=r){
150         if(a[i].x>a[j].x||(a[i].x==a[j].x&&a[i].ins)){
151             if(a[i].ins)add2(n-a[i].y+1,g[a[i].id]);
152             i++;
153         }
154         else{
155             if(!a[j].ins)g[a[j].id]+=query2(n-a[j].y+1);
156             j++;
157         }
158     }
159     while(i<=mid){
160         if(a[i].ins)add2(n-a[i].y+1,g[a[i].id]);
161         i++;
162     }
163     while(j<=r){
164         if(!a[j].ins)g[a[j].id]+=query2(n-a[j].y+1);
165         j++;
166     }
167     for(i=l;i<=mid;i++)if(a[i].ins)clear2(n-a[i].y+1);
168     CDQ2(mid+1,r);
169 }
170 void CDQ3(int l,int r){
171     if(l>=r)return;
172     int mid=(l+r)>>1;
173     CDQ3(mid+1,r);
174     copy(b+l,b+r+1,a+l);
175     sort(a+l,a+mid+1);
176     sort(a+mid+1,a+r+1);
177     int i=mid+1,j=l;
178     while(i<=r&&j<=mid){
179         if(a[i].x<a[j].x||(a[i].x==a[j].x&&a[i].ins)){
180             if(a[i].ins)add2(a[i].y,h[a[i].id]);
181             i++;
182         }
183         else{
184             if(!a[j].ins)h[a[j].id]+=query2(a[j].y);
185             j++;
186         }
187     }
188     while(i<=r){
189         if(a[i].ins)add2(a[i].y,h[a[i].id]);
190         i++;
191     }
192     while(j<=mid){
193         if(!a[j].ins)h[a[j].id]+=query2(a[j].y);
194         j++;
195     }
196     for(int i=mid+1;i<=r;i++)if(a[i].ins)clear2(a[i].y);
197     CDQ3(l,mid);
198 }
199 void add1(int x,int d){
200     while(x<=n){
201         c1[x]=max(c1[x],d);
202         x+=x&-x;
203     }
204 }
205 void add2(int x,long double d){
206     while(x<=n){
207         c2[x]+=d;
208         x+=x&-x;
209     }
210 }
211 int query1(int x){
212     int ans=0;
213     while(x){
214         ans=max(ans,c1[x]);
215         x&=x-1;
216     }
217     return ans;
218 }
219 long double query2(int x){
220     long double ans=0.0;
221     while(x){
222         ans+=c2[x];
223         x&=x-1;
224     }
225     return ans;
226 }
227 void clear1(int x){
228     while(x<=n){
229         c1[x]=0;
230         x+=x&-x;
231     }
232 }
233 void clear2(int x){
234     while(x<=n){
235         c2[x]=0.0;
236         x+=x&-x;
237     }
238 }
View Code

有一些做法可以一边分治一边求出$g$,然后再跑一遍分治就能求出$h$,可以减少代码量?听说lrd写的就是这个?表示还没理解清楚……

posted @ 2017-02-19 19:17  AntiLeaf  阅读(137)  评论(0编辑  收藏  举报