拦截导弹(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
原文地址:https://www.cnblogs.com/Wwb123/p/11299726.html