[BZOJ2244][SDOI2011]拦截导弹(dp+cdq分治)
2017-03-26 21:45
483 查看
题目描述
传送门题解
这题真tm麻烦其实dp是很简单的,令f(i)表示以i为结尾的最长非升子序列长度,g(i)表示以i结尾的最长非升子序列的方案数,h(i)和k(i)分别表示以i为开头的
然后对于每一个i,判断f(i)+h(i)-1是否就是最长答案;如果是,那么g(i)*k(i)就是这个点出现的次数
dp的过程用两个cdq做一下就行,实际上就是一个三维偏序,按照时间分治,每次按照横坐标排序,然后纵坐标用bit查询一下
这题好像精度有什么问题…全改成double就过了…
代码
#include<algorithm> #include<iostream> #include<cstring> #include<cstdio> #include<cmath> using namespace std; #define N 100005 #define LL long long int n; double ans,down; int lsh ,LSH; struct data{int x,y,id;}q ; double f ,h ,g ,k ; namespace FG { double C ,D ; double maxf,maxg; data a ,b ;int ch ; int cmp(data a,data b) { return a.x>b.x; } void add(int loc,double valf,double valg) { for (int i=loc;i<=LSH;i+=i&-i) if (valf>C[i]) C[i]=valf,D[i]=valg; else if (valf==C[i]) D[i]+=valg; } void query(int loc) { maxf=0,maxg=0; for (int i=loc;i>=1;i-=i&-i) if (C[i]>maxf) maxf=C[i],maxg=D[i]; else if (C[i]==maxf) maxg+=D[i]; } void cover(int loc) { for (int i=loc;i<=LSH;i+=i&-i) C[i]=0,D[i]=0; } void cdq(int l,int r) { if (l==r) { f[l]=max(f[l],1.0); g[l]=max(g[l],1.0); return; } int mid=(l+r)>>1; cdq(l,mid); int acnt=0,bcnt=0; for (int i=l;i<=mid;++i) a[++acnt]=q[i]; for (int i=mid+1;i<=r;++i) b[++bcnt]=q[i]; sort(a+1,a+acnt+1,cmp);sort(b+1,b+bcnt+1,cmp); int pa=1,pb=1,tot=0; while (pb<=bcnt) { while (pa<=acnt&&a[pa].x>=b[pb].x) { add(LSH-a[pa].y+1,f[a[pa].id],g[a[pa].id]); ch[++tot]=LSH-a[pa].y+1; ++pa; } query(LSH-b[pb].y+1); int now=b[pb].id; if (f[now]<maxf+1) f[now]=maxf+1,g[now]=maxg; else if (f[now]==maxf+1) g[now]+=maxg; ++pb; } for (int i=1;i<=tot;++i) cover(ch[i]); cdq(mid+1,r); } void solve() { cdq(1,n); } } namespace HK { double C ,D ; double maxh,maxk; data a ,b ;int ch ; int cmp(data a,data b) { return a.x>b.x; } void add(int loc,double valh,double valk) { for (int i=loc;i<=LSH;i+=i&-i) if (valh>C[i]) C[i]=valh,D[i]=valk; else if (valh==C[i]) D[i]+=valk; } void query(int loc) { maxh=0,maxk=0; for (int i=loc;i>=1;i-=i&-i) if (C[i]>maxh) maxh=C[i],maxk=D[i]; else if (C[i]==maxh) maxk+=D[i]; } void cover(int loc) { for (int i=loc;i<=LSH;i+=i&-i) C[i]=0,D[i]=0; } void cdq(int l,int r) { if (l==r) { h[l]=max(h[l],1.0); k[l]=max(k[l],1.0); return; } int mid=(l+r)>>1; cdq(mid+1,r); int acnt=0,bcnt=0; for (int i=l;i<=mid;++i) a[++acnt]=q[i]; for (int i=mid+1;i<=r;++i) b[++bcnt]=q[i]; sort(a+1,a+acnt+1,cmp);sort(b+1,b+bcnt+1,cmp); int pa=acnt,pb=bcnt,tot=0; while (pa>=1) { while (pb>=1&&b[pb].x<=a[pa].x) { add(b[pb].y,h[b[pb].id],k[b[pb].id]); ch[++tot]=b[pb].y; --pb; } query(a[pa].y); int now=a[pa].id; if (h[now]<maxh+1) h[now]=maxh+1,k[now]=maxk; else if (h[now]==maxh+1) k[now]+=maxk; --pa; } for (int i=1;i<=tot;++i) cover(ch[i]); cdq(l,mid); } void solve() { cdq(1,n); } } int main() { scanf("%d",&n); for (int i=1;i<=n;++i) { scanf("%d%d",&q[i].x,&q[i].y); lsh[++LSH]=q[i].y;q[i].id=i; } sort(lsh+1,lsh+LSH+1);LSH=unique(lsh+1,lsh+LSH+1)-lsh-1; for (int i=1;i<=n;++i) q[i].y=lower_bound(lsh+1,lsh+LSH+1,q[i].y)-lsh; for (int i=1;i<=n;++i) f[1]=1;g[1]=1; FG::solve(); for (int i=1;i<=n;++i) ans=max(ans,f[i]); printf("%.0lf\n",ans); for (int i=1;i<=n;++i) if (f[i]==ans) down+=g[i]; h =1;k =1; HK::solve(); double zero=0.0; for (int i=1;i<=n;++i) if (f[i]+h[i]-1==ans) printf("%.5lf%c",g[i]*k[i]/down," \n"[i==n]); else printf("%.5lf%c",zero," \n"[i==n]); }
相关文章推荐
- [BZOJ2244][SDOI2011]拦截导弹(DP+CDQ分治)
- bzoj 2244 [SDOI2011]拦截导弹(DP+CDQ分治+BIT)
- bzoj 2244 [SDOI2011]拦截导弹(dp+CDQ+树状数组)
- BZOJ2244 & Codevs1822 [SDOI2011]拦截导弹
- BZOJ 2244: [SDOI2011]拦截导弹 DP+CDQ分治
- Bzoj2244 [SDOI2011]拦截导弹
- [CDQ分治] BZOJ 2244 [SDOI2011]拦截导弹
- [BZOJ2244][SDOI2011]拦截导弹-CDQ分治-树状数组
- [BZOJ2244][SDOI2011]拦截导弹 CDQ分治
- BZOJ 2244 [SDOI2011]拦截导弹 ——CDQ分治
- bzoj 2244: [SDOI2011]拦截导弹
- bzoj 2244 [SDOI2011]拦截导弹
- 【BZOJ2244】【SDOI2011】拦截导弹
- [BZOJ2244][SDOI2011]拦截导弹
- bzoj2244[SDOI2011]拦截导弹
- BZOJ 2244 SDOI2011 拦截导弹 CDQ分治/二维树状数组
- [BZOJ]2244: [SDOI2011]拦截导弹 DP+CDQ分治+树状数组
- BZOJ 2244: [SDOI2011]拦截导弹 [CDQ分治 树状数组]
- BZOJ2244 [SDOI2011]拦截导弹 【cdq分治 + 树状数组】
- bzoj2244[SDOI2011]拦截导弹