bzoj 2244[SDOI 2011]迎撃ミサイル(DP+CDQ分割+BIT)
21970 ワード
【テーマリンク】
http://www.lydsy.com/JudgeOnline/problem.php?id=2244
【題意】
n個の二元組を与えて、最長でサブシーケンスと各ミサイルがブロックされる確率を求めます.
【考え方】
DP+CDQ分割+BIT
まずシーケンスを反転して、lisを求めるのは便利です.
第一の質問に対して、私達が要求しているのは
f[i]=max{f[j]}、j<i、x[j]<x[i]、y[j]<y[i]
満足すべき条件は三次元偏順であり,CDQで分割して解くことができることが分かった.
第二の問題を発見するのは簡単ではないです.一つのミサイルがあるlisの数/全部のlisの数です.つのミサイルのありかのlisは自分を含まなければならなくて、だから私達はg[i]を設定してiを最後のlisの総数にして、移動式があります:
g[i]=sigma{g[j]、j CDQで分割してもいいです.最後のfの関係に気づいたら、これまでの最大のlis値を集計してfと比較すればいいと思います.
似ているものはg’f’を求めることができます.全部g fの逆の定義です.つまりiで始まる…
奇術淫巧:反転してシーケンスに反対を取ってもいいです.このように関数を使って辛くてもいいです.離散化してから速く走って、一気にrk 3に上がります.
【コード】
1 #include<cstdio>
2 #include<cstring>
3 #include<iostream>
4 #include<algorithm>
5 #define FOR(a,b,c) for(int a=b;a<=c;a++)
6 using namespace std;
7
8 const int N = 1e5+10;
9
10 struct Node {
11 int id,x,y;
12 bool operator<(const Node& rhs)const {
13 return x<rhs.x||(x==rhs.x&&y<rhs.y);
14 }
15 }q[N],t[N];
16 bool cmp(const Node& a,const Node& b)
17 {
18 return a.id<b.id;
19 }
20
21 int f[2][N]; double g[2][N],ans[N];
22 int hash[N],tot,n;
23
24
25 int read()
26 {
27 char c=getchar(); int x=0; int f=1;
28 while(!isdigit(c)){if(c=='-')f=-1; c=getchar();}
29 while(isdigit(c)) x=x*10+c-'0',c=getchar();
30 return x*f;
31 }
32
33 int t_f[N],tag[N],T; double t_g[N];
34 void add(int x,int f,double g)
35 {
36 for(;x<=tot;x+=x&-x) {
37 if(tag[x]!=T) {tag[x]=T;t_f[x]=0;t_g[x]=0;}
38 if(f>t_f[x]){t_f[x]=f;t_g[x]=g;}
39 else if(f==t_f[x]) t_g[x]+=g;
40 }
41 }
42 void query(int x,int& mx,double& sum)
43 {
44 mx=0; sum=0.0;
45 for(;x;x-=x&-x) if(tag[x]==T){
46 if(t_f[x]>mx) {
47 mx=t_f[x]; sum=t_g[x];
48 } else if(t_f[x]==mx)
49 sum+=t_g[x];
50 }
51 }
52
53 void solve(int l,int r,int ty)
54 {
55 if(l==r) {
56 if(!f[ty][l]){
57 f[ty][l]=1; g[ty][l]=1;
58 }
59 return ;
60 }
61 int mid=(l+r)>>1;
62 int l1=l,l2=mid+1,i,j,cnt=0;
63 for(i=l;i<=r;i++) {
64 if(q[i].id<=mid) t[l1++]=q[i];
65 else t[l2++]=q[i];
66 }
67 memcpy(q+l,t+l,sizeof(Node)*(r-l+1));
68 solve(l,mid,ty);
69 T++;
70 sort(q+mid+1,q+r+1);
71 for(i=mid+1,j=l;i<=r;i++)
72 {
73 int id;
74 for(;j<=mid&&q[j].x<=q[i].x;j++) {
75 id=q[j].id; cnt++;
76 add(q[j].y,f[ty][id],g[ty][id]);
77 }
78 int mx; double sum;
79 query(q[i].y,mx,sum);
80 id=q[i].id;
81 if(mx>0) {
82 if(mx+1>f[ty][id]) {
83 f[ty][id]=mx+1; g[ty][id]=sum;
84 } else if(mx+1==f[ty][id]) {
85 g[ty][id]+=sum;
86 }
87 }
88 }
89 solve(mid+1,r,ty);
90 l1=l,l2=mid+1; int now=l;
91 while(l1<=mid||l2<=r) {
92 if(l2>r||l1<=mid&&q[l1]<q[l2]) t[now++]=q[l1++];
93 else t[now++]=q[l2++];
94 }
95 memcpy(q+l,t+l,sizeof(Node)*(r-l+1));
96 }
97
98 int main()
99 {
100 //freopen("in.in","r",stdin);
101 //freopen("out.out","w",stdout);
102 n=read();
103 int mxx=0;
104 FOR(i,1,n)
105 {
106 q[i].x=read(),q[i].y=read();
107 hash[i]=q[i].y;
108 mxx=max(mxx,q[i].x);
109 }
110 sort(hash+1,hash+n+1);
111 tot=unique(hash+1,hash+n+1)-hash-1;
112 FOR(i,1,n)
113 q[i].y=lower_bound(hash+1,hash+tot+1,q[i].y)-hash;
114 reverse(q+1,q+n+1);
115 FOR(i,1,n) q[i].id=i;
116 solve(1,n,0);
117
118 sort(q+1,q+n+1,cmp);
119 reverse(q+1,q+n+1);
120 FOR(i,1,n)
121 q[i].x=mxx-q[i].x+1,q[i].y=tot-q[i].y+1,
122 q[i].id=i;
123 solve(1,n,1);
124 int mx=0; double sum=0;
125 FOR(i,1,n) {
126 int tmp=f[0][i];
127 if(tmp>mx) {
128 mx=tmp; sum=g[0][i]*g[1][n-i+1];
129 } else if(tmp==mx)
130 sum+=g[0][i]*g[1][n-i+1];
131 }
132 printf("%d
",mx);
133 for(int i=n;i;i--) {
134 if(f[0][i]+f[1][n-i+1]-1==mx) {
135 ans[i]=(g[0][i]*g[1][n-i+1])/sum;
136 } else ans[i]=0;
137 }
138 for(int i=n;i>1;i--) printf("%.5lf ",ans[i]);
139 printf("%.5lf",ans[1]);
140 return 0;
141 }