• 拦截导弹(CDQ分治,DP)


    很好的题,值得细细说,(果然又是个假期望).......

    首先我们提取信息,显然这是个三维偏序问题

    用简单的DP式子表示需要满足

    f[i]=max(f[1--j]+1)(v[j]<v[i],h[j]<h[i],j<i)

    那么我们发现这样可以愉快的CDQ,方案数用g数组表示,

    在树状数组中注意维护就好

    void add(int x,int kx,double kxx)
    {
        for(int i=x;i<=h_tot;i+=lowbit(i))
        { 
            if(kx==c[i])
            {
                c2[i]+=kxx;
            }
            else if(kx>c[i])
            {
                c2[i]=kxx;c[i]=kx;
            }
        }
    }

    (注意这里+的方案数,是当前增加的值的方案数)

    这样就结束了????

    在这里才发现了CDQ优化DP的方法有些不同

       我们发现普通的CDQ是将子区间处理完后,才会处理更大的区间

    然而这里有一些不同的是,我们并不能一个一个小区间的处理

    例如一串数 1 2 3 4 5 6

    如果我们先处理左区间1-3在处理右区间4-6,在处理最后

    我们发现可能的结果是1-3先更新4,5,

    然后4,5更新6,显然这样是满足DP规律的

    我们不妨将其看作中序遍历,先左后中后右,这样保证了正确性QAQ

    注意:

       这样就不能像原来一样保证序列的有序,这样我们牺牲时间

    每次处理新区间时,将左右两区间按第二关键字排序一遍

    然后处理完后早将这个的大区间按第一关键字排回,这样保证有序

    (原来区间从下向上第一关键字当然有序,这时先大区间后小区间就要重新排了)

    还有我们要两次扫,因为假设是1-n搜表示以i结尾的最大不上升序列长度

    然而我们的i可能卡在中间,那么我们把区间倒转,再将每个a[i]变值(原来小的变成大的),然后只要打一遍CDQ就好了

      1 #include<iostream>
      2 #include<cstdio>
      3 #include<string>
      4 #include<algorithm>
      5 #include<cmath>
      6 #include<vector>
      7 #include<map>
      8 #include<cstring>
      9 #define MAXN 510001
     10 #define int long long 
     11 using namespace std;
     12 struct node{int v,h,id;}e[MAXN];
     13 int lowbit(int x){return x&(-x);}
     14 bool cmp(const node &a,const node &b)     {return a.id<b.id;}
     15 int h_tot,v_tot;
     16 int c[MAXN];
     17 double c2[MAXN];
     18 int dp[MAXN][3];
     19 double g[MAXN][3];
     20 int v_old[MAXN],h_old[MAXN];
     21 int n;int maxn=0;
     22 double geshu=0.0;
     23 double ans[MAXN];
     24 void add(int x,int kx,double kxx)
     25 {
     26     for(int i=x;i<=h_tot;i+=lowbit(i))
     27     { 
     28         if(kx==c[i])
     29         {
     30             c2[i]+=kxx;
     31         }
     32         else if(kx>c[i])
     33         {
     34             c2[i]=kxx;c[i]=kx;
     35         }
     36     }
     37 }
     38 int query(int x)
     39 {
     40     int anss=0;
     41     for(int i=x;i>=1;i-=lowbit(i))
     42     {
     43         if(c[i]>anss)
     44         {
     45             geshu=c2[i];anss=c[i];
     46         }
     47         else if(c[i]==anss)
     48         {
     49             geshu+=c2[i];
     50         }
     51     }
     52     return anss;
     53 }
     54 void clear(int x)
     55 {
     56     for(int i=x;i<=h_tot;i+=lowbit(i)){c[i]=0;c2[i]=0.0;}
     57 }
     58 bool cmp_v(const node &a,const node &b)
     59 {
     60     return (a.v==b.v)?((a.h==b.h)?(a.id<b.id):a.h<b.h):(a.v<b.v);
     61 }
     62 void work1(int l,int r,int mid,int me)
     63 {
     64     sort(e+l,e+r+1,cmp_v);
     65     for(int i=l;i<=r;++i)
     66     {
     67         if(e[i].id<=mid)
     68         {
     69             add(e[i].h,dp[e[i].id][me],g[e[i].id][me]);
     70         }
     71         else
     72         {
     73             geshu=0;
     74             int ttt=query(e[i].h)+1;
     75             if(ttt>dp[e[i].id][me])
     76             {
     77                dp[e[i].id][me]=ttt;
     78                g[e[i].id][me]=geshu;
     79             }
     80             else if(ttt==dp[e[i].id][me])
     81             {
     82                g[e[i].id][me]+=geshu;  
     83             }
     84         }
     85     }
     86     for(int i=l;i<=r;++i)
     87     {
     88         if(e[i].id<=mid)
     89            clear(e[i].h);
     90     }
     91     sort(e+l,e+r+1,cmp);
     92 }
     93 void solve(int l,int r,int me)
     94 {
     95     int mid=(l+r)>>1;
     96     if(l==r)return ;
     97     solve(l,mid,me);
     98     work1(l,r,mid,me);
     99     solve(mid+1,r,me);
    100     return ;
    101 }
    102 signed main()
    103 {
    104     scanf("%lld",&n);
    105     for(int i=1;i<=n;++i)
    106     {
    107         scanf("%lld%lld",&h_old[n-i+1],&v_old[n-i+1]);
    108         e[n-i+1].h=h_old[n-i+1];
    109         e[n-i+1].v=v_old[n-i+1];
    110         e[n-i+1].id=n-i+1;
    111     }
    112     sort(h_old+1,h_old+n+1);
    113     sort(v_old+1,v_old+n+1);
    114     h_tot=unique(h_old+1,h_old+n+1)-h_old-1;
    115     v_tot=unique(v_old+1,v_old+n+1)-v_old-1;
    116     for(int i=1;i<=n;++i)
    117     { 
    118          e[i].h=lower_bound(h_old+1,h_old+h_tot+1,e[i].h)-h_old;
    119          e[i].v=lower_bound(v_old+1,v_old+v_tot+1,e[i].v)-v_old;
    120     }
    121     for(int i=1;i<=n;++i)
    122     {
    123          dp[e[i].id][1]=1;dp[e[i].id][2]=1;
    124          g[e[i].id][1]=1;g[e[i].id][2]=1;
    125     }
    126     sort(e+1,e+n+1,cmp);
    127     solve(1,n,1);
    128     /*for(int i=1;i<=n;++i)
    129     {
    130         printf("dp[%lld][1]=%lld g[%lld][1]=%lld 
    ",i,dp[i][1],i,g[i][1]);
    131     }*/
    132     for(int i=1;i<=n;++i)
    133         maxn=max(maxn,dp[i][1]);
    134     reverse(e+1,e+n+1);
    135     for(int i=1;i<=n;++i)
    136     {
    137         e[i].h=h_tot-e[i].h+1;
    138         e[i].v=v_tot-e[i].v+1;
    139         e[i].id=i;
    140     }
    141     solve(1,n,2);
    142     double sum=0.0;  
    143     for(int i=1;i<=n;++i)
    144     {
    145         if(dp[i][1]==maxn)sum+=g[i][1];
    146     }
    147     for(int i=1;i<=n;++i)
    148     {
    149          if(dp[n-i+1][2]+dp[i][1]-1==maxn)
    150          {
    151               ans[i]=(g[i][1]*g[n-i+1][2])/sum;
    152               //printf("ans[%lld]=%.4lf
    ",i,ans[i]);
    153          }
    154          else ans[i]=0.0;
    155     }
    156     printf("%lld
    ",maxn);
    157     for(int i=n;i>=1;--i)
    158     {
    159          printf("%.5lf ",ans[i]);
    160     }
    161     cout<<endl;
    162 }
    View Code
  • 相关阅读:
    NIO通道的学习笔记
    Struts学习笔记(启动过程)
    Struts2学习笔记(ResultType)
    11
    编写类String的构造函数、析构函数和赋值函数(转载)
    new与malloc的区别
    不用判断语句,求两个数中大的那个
    delete p和delete[] p的区别(转)
    (转)虚函数和纯虚函数区别
    不借助第三个变量交换两个整数的值
  • 原文地址:https://www.cnblogs.com/Wwb123/p/11299726.html
Copyright © 2020-2023  润新知