zoukankan      html  css  js  c++  java
  • bzoj 2244 [SDOI2011]拦截导弹(dp+CDQ+树状数组)

    传送门

    题解

    看了半天完全没发现这东西和CDQ有什么关系……

    先把原序列翻转,求起来方便

    然后把每一个位置表示成$(a,b,c)$其中$a$表示位置,$b$表示高度,$c$表示速度,求有多少个位置$a,b,c$都小于它,这就是一个三维偏序问题,直接CDQ就可以解决了……

    然后考虑如何求第二问,就是一个导弹所在的LIS数/总的LIS数,因为一个导弹的LIS必须包含自己,以$g[i]$表示以$i$结尾的LIS总数,不难发现有如下转移式

    $$g[i]=sum g[j] { (i<j,h[i]<h[j],v[i]<v[j],f[j]+1=f[i]}$$

    这个也可以用CDQ来解决,只要统计出之前最大的LIS再和$f$比较就好了(完全没想出来怎么会这么神仙……)

    然后再求出以$i$为开头的LIS长度和方案数,两个相乘就是他自己的方案数了

    代码好长……调了好久……

      1 //minamoto
      2 #include<bits/stdc++.h>
      3 using namespace std;
      4 #define getc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
      5 char buf[1<<21],*p1=buf,*p2=buf;
      6 template<class T>inline bool cmax(T&a,const T&b){return a<b?a=b,1:0;}
      7 inline int read(){
      8     #define num ch-'0'
      9     char ch;bool flag=0;int res;
     10     while(!isdigit(ch=getc()))
     11     (ch=='-')&&(flag=true);
     12     for(res=num;isdigit(ch=getc());res=res*10+num);
     13     (flag)&&(res=-res);
     14     #undef num
     15     return res;
     16 }
     17 const int N=50005;
     18 struct BIT{
     19     int f;double w;
     20     BIT(){f=0,w=0;}
     21     BIT(int f,double w):f(f),w(w){}
     22 }c[N];
     23 int n,st[N],top=0;
     24 inline void add(int x,int f,double w){
     25     for(int i=x;i<=n;i+=i&-i){
     26         if(c[i].f<f){
     27             if(c[i].f==0) st[++top]=i;
     28             c[i]=(BIT){f,w};
     29         }
     30         else if(c[i].f==f) c[i].w+=w;
     31     }
     32 }
     33 inline BIT query(int x){
     34     BIT res;
     35     for(int i=x;i;i-=i&-i){
     36         if(c[i].f>res.f) res=c[i];
     37         else if(c[i].f==res.f) res.w+=c[i].w;
     38     }
     39     return res;
     40 }
     41 struct node{
     42     int h,v,id,t;
     43     int f[2];double g[2];
     44 }a[N],q[N];
     45 int wh[N],wv[N],id[N],rk[N];
     46 inline bool cmp(int i,int j)
     47 {return a[i].h<a[j].h||(a[i].h==a[j].h&&a[i].id<a[j].id);}
     48 inline bool cmpid(const node &a,const node &b)
     49 {return a.id<b.id;}
     50 void solve(int l,int r,int t){
     51     if(l==r){
     52         if(a[l].f[t]<1) a[l].f[t]=a[l].g[t]=1;
     53         return;
     54     }
     55     int mid=(l+r)>>1;
     56     memcpy(q+l,a+l,sizeof(node)*(r-l+1));
     57     int q1=l,q2=mid+1;
     58     for(int i=l;i<=r;++i){
     59         q[i].t<=mid?a[q1++]=q[i]:a[q2++]=q[i];
     60     }
     61     solve(l,mid,t);
     62     q1=l;
     63     for(int i=mid+1;i<=r;++i){
     64         while(q1<=mid&&a[q1].id<a[i].id) add(a[q1].v,a[q1].f[t],a[q1].g[t]),++q1;
     65         BIT res=query(a[i].v);
     66         if(res.f==0) continue;
     67         if(res.f+1>a[i].f[t]){
     68             a[i].f[t]=res.f+1,a[i].g[t]=res.w;
     69         }
     70         else if(res.f+1==a[i].f[t]) a[i].g[t]+=res.w;
     71     }
     72     while(top){c[st[top--]]=(BIT){0,0};}
     73     solve(mid+1,r,t);
     74     merge(a+l,a+mid+1,a+mid+1,a+r+1,q+l,cmpid);
     75     memcpy(a+l,q+l,sizeof(node)*(r-l+1));
     76 }
     77 int th=0,tv=0;
     78 int main(){
     79     //freopen("testdata.in","r",stdin);
     80     n=read();
     81     for(int i=1;i<=n;++i){
     82         wh[i]=a[i].h=read(),wv[i]=a[i].v=read(),a[i].id=i,rk[i]=i;
     83     }
     84     sort(wh+1,wh+1+n),sort(wv+1,wv+1+n);
     85     th=unique(wh+1,wh+1+n)-wh-1,tv=unique(wv+1,wv+1+n)-wv-1;
     86     for(int i=1;i<=n;++i){
     87         a[i].h=th-(lower_bound(wh+1,wh+th+1,a[i].h)-wh)+1;
     88         a[i].v=tv-(lower_bound(wv+1,wv+tv+1,a[i].v)-wv)+1;
     89     }
     90     sort(rk+1,rk+1+n,cmp);
     91     for(int i=1;i<=n;++i) a[rk[i]].t=i;
     92     solve(1,n,0);
     93     for(int i=1;i<=n;++i){
     94         a[i].h=th-a[i].h+1;
     95         a[i].v=tv-a[i].v+1;
     96         a[i].id=n-a[i].id+1;
     97         a[i].t=n-a[i].t+1;
     98     }
     99     reverse(a+1,a+1+n);
    100     solve(1,n,1);
    101     reverse(a+1,a+1+n);
    102     double sum=0;int ans=0;
    103     for(int i=1;i<=n;++i){
    104         int len=a[i].f[0]+a[i].f[1]-1;
    105         cmax(ans,len);
    106     }
    107     printf("%d
    ",ans);
    108     for(int i=1;i<=n;++i){
    109         if(a[i].f[0]==ans) sum+=a[i].g[0]*a[i].g[1];
    110     }
    111     for(int i=1;i<=n;++i){
    112         double res=a[i].g[0]*a[i].g[1];
    113         printf("%.5lf ",(a[i].f[0]+a[i].f[1]-1==ans)?(res/sum):0);
    114     }
    115     return 0;
    116 }
  • 相关阅读:
    C#跨窗体操作(引用传递)
    C#中使用自定义消息
    WebService基于SoapHeader实现安全认证[webservice][.net][安全][soapheader]
    C#webBrowser实现在新选项卡打开链接
    ASP.NET FormsAuthentication跨站点登录时绝对地址返回的问题
    winform 实现TextBox 关键字智能提示
    SQL批量上传海量数据的存储过程
    优化SQL 语句 in 和not in 的替代方案
    (转)CMMI+人性化管理=软件流程改善成功之道
    两个ComboBox互相联动的一种解决方法
  • 原文地址:https://www.cnblogs.com/bztMinamoto/p/9459177.html
Copyright © 2011-2022 走看看