• bzoj2244[SDOI2011]拦截导弹


    题意:最长不上升子序列,但有两个关键字.求:1.最长不上升子序列的长度 2.随机在最长不上升子序列中选取一个,问某个位置被选中的概率.

    调到快怀疑人生最后发现把printf(“%.8f”,0)改成printf(“%.8f”,0.0”)就能过了……论学好输入输出的必要性….

    记f[0][i]表示以位置i结尾的最长不上升子序列长度,f[1][i]表示从i开始的最长不上升子序列长度.

    可以发现第二问只要算出以每个位置开始和结束的最长不上升子序列的方案数g[0][i]和g[1][i],如果f[0][i]+f[1][i]-1等于整个序列的最长不上升子序列长度,那么i出现的概率为g[0][i]*g[1][i]/(所有的最长不上升子序列种数)

    f数组只需要正反两遍cdq分治就可以求出.对于g数组,我们回忆一个关键字的最长不上升子序列方案数的求法,可以和f数组一起dp.只要在树状数组每个位置同时维护一段区间的最大值和最大值的数目就可以了.

    Cdq分治的时候细节不会处理我就大力sort…不过还是O(nlog^2n)的.

    方案数用double存就可以过

    #include<cstdio>
    #include<algorithm>
    using namespace std;
    typedef long double ll;
    const int maxn=50005;
    int Max[maxn];ll cntMax[maxn];
    void Add1(int x,int w,ll cnt){
      for(;x;x-=x&(-x)){
        if(Max[x]==w){
          cntMax[x]+=cnt;
        }else if(Max[x]<w){
          Max[x]=w;cntMax[x]=cnt;
        }
      }
    }
    int qMax1(int x){
      int ans=0;
      for(;x<maxn;x+=x&(-x))if(Max[x]>ans)ans=Max[x];
      return ans;
    }
    ll qSum1(int x,int M){
      ll ans=0;
      for(;x<maxn;x+=x&(-x))if(Max[x]==M)ans+=cntMax[x];
      return ans;
    }
    void del1(int x){
      for(;x;x-=x&(-x))Max[x]=cntMax[x]=0;
    }
    void Add2(int x,int w,ll cnt){
      for(;x<maxn;x+=x&(-x)){
        if(Max[x]==w){
          cntMax[x]+=cnt;
        }else if(Max[x]<w){
          Max[x]=w;cntMax[x]=cnt;
        }
      }
    }
    int qMax2(int x){
      int ans=0;
      for(;x;x-=x&(-x))if(Max[x]>ans)ans=Max[x];
      return ans;
    }
    ll qSum2(int x,int M){
      ll ans=0;
      for(;x;x-=x&(-x))if(Max[x]==M)ans+=cntMax[x];
      return ans;
    }
    void del2(int x){
      for(;x<maxn;x+=x&(-x))Max[x]=cntMax[x]=0;
    }
    int h[2][maxn],v[2][maxn];
    int f[2][maxn];ll g[2][maxn];
    int seq[maxn];
    bool cmp1(const int &a,const int &b){
      return h[0][a]<h[0][b];
    }
    bool cmp2(const int &a,const int &b){
      return v[0][a]<v[0][b];
    }
    void cdq1(int l,int r){
      if(l==r)return;
      int mid=(l+r)>>1;
      cdq1(l,mid);
      for(int i=l;i<=r;++i)seq[i]=i;
      sort(seq+l,seq+mid+1,cmp2);
      sort(seq+mid+1,seq+r+1,cmp2);
      int pt=mid;
      for(int i=r;i>mid;--i){
        while(pt>=l&&v[0][seq[pt]]>=v[0][seq[i]]){
          Add1(h[0][seq[pt]],f[0][seq[pt]],g[0][seq[pt]]);
          --pt;
        }
        int tmpmax=qMax1(h[0][seq[i]]);
        if(tmpmax+1>f[0][seq[i]]){
          f[0][seq[i]]=tmpmax+1;g[0][seq[i]]=qSum1(h[0][seq[i]],tmpmax);
        }else if(tmpmax+1==f[0][seq[i]]){
          g[0][seq[i]]+=qSum1(h[0][seq[i]],tmpmax);
        }
      }
      for(int i=mid;i>pt;--i)del1(h[0][seq[i]]);
      cdq1(mid+1,r);
      sort(seq+l,seq+r+1,cmp2);
    }
    bool cmp3(const int &a,const int &b){
      return v[1][a]<v[1][b];
    }
    void cdq2(int l,int r){
      if(l==r)return;
      int mid=(l+r)>>1;
      cdq2(l,mid);
      for(int i=l;i<=r;++i)seq[i]=i;
      sort(seq+mid+1,seq+r+1,cmp3);
      sort(seq+l,seq+mid+1,cmp3);
      int pt=l;
      for(int i=mid+1;i<=r;++i){
        while(pt<=mid&&v[1][seq[pt]]<=v[1][seq[i]]){
          Add2(h[1][seq[pt]],f[1][seq[pt]],g[1][seq[pt]]);
          ++pt;
        }
        int tmpmax=qMax2(h[1][seq[i]]);
        if(tmpmax+1>f[1][seq[i]]){
          f[1][seq[i]]=tmpmax+1;g[1][seq[i]]=qSum2(h[1][seq[i]],tmpmax);
        }else if(tmpmax+1==f[1][seq[i]]){
          g[1][seq[i]]+=qSum2(h[1][seq[i]],tmpmax);
        }
      }
      for(int i=l;i<pt;++i)del2(h[1][seq[i]]);
      cdq2(mid+1,r);
      sort(seq+l,seq+r+1,cmp3);
    }
    int main(){
      int n;scanf("%d",&n);
      for(int i=1;i<=n;++i)scanf("%d%d",&h[0][i],&v[0][i]);
      for(int i=1;i<=n;++i)seq[i]=i;
      sort(seq+1,seq+n+1,cmp1);
      int tot=0,old=-1;
      for(int i=1;i<=n;++i){
        if(old!=h[0][seq[i]]){
          old=h[0][seq[i]];++tot;
        }
        h[0][seq[i]]=tot;
      }
      for(int i=1;i<=n;++i){
        h[1][i]=h[0][n-i+1];v[1][i]=v[0][n-i+1];
      }
      for(int i=1;i<=n;++i)seq[i]=i;
      for(int i=1;i<=n;++i)f[0][i]=f[1][i]=g[0][i]=g[1][i]=1;
      cdq1(1,n);cdq2(1,n);
      int ans=0;
      for(int i=1;i<=n;++i){
        if(f[0][i]>ans)ans=f[0][i];
      }
      printf("%d
    ",ans);
      ll sum=0;
      for(int i=1;i<=n;++i){
        if(f[0][i]==ans)sum+=g[0][i];
      }
      for(int i=1;i<=n;++i){
        if(f[0][i]+f[1][n-i+1]-1!=ans)printf("%.8f ",0.0);
        else printf("%.8f ",double(g[0][i]*g[1][n-i+1]/(sum)));
      }
      return 0;
    }
  • 相关阅读:
    线段树(区间合并) LA 3989 "Ray, Pass me the dishes!"
    BIT LA 4329 Ping pong
    并查集(路径更新) LA 3027 Corporative Network
    log4j.properties配置详解与实例-全部测试通过
    ActiveMQ入门实例
    activemq安全设置 设置admin的用户名和密码
    Freemarker入门小案例(生成静态网页的其中一种方式)
    maven项目在myeclipse中不出现Maven Dependencies 和maven标识的解决方法
    Mysql,SqlServer,Oracle主键自动增长的设置
    常用SQL语句
  • 原文地址:https://www.cnblogs.com/liu-runda/p/6416195.html
Copyright © 2020-2023  润新知