「SDOI2011」分割統治迎撃ミサイルCDQ +フェンウィックツリー

質問の意味:

ミサイル迎撃システムを開発するために、敵のミサイル攻撃を防御するために国。最初のラウンドの任意の高さに到達することができ、迎撃ミサイルの任意の速度であってもよいが、フロントシェルのうちの各々は、切片の高さよりも高くはない。しかし、このシステムは、欠陥迎撃ミサイルを有しますミサイルの飛行速度が仕える前の最初のものより大きくすることはできません。ある日、レーダーは、入ってくる敵のミサイルを拾いました。システムとして、ベータまだそう唯一のシステムであるため、すべてのミサイルを迎撃しないことができます。

すべてのミサイルを迎撃しない場合には、当然のことながら、私たちはミサイルを迎撃するためのプログラムの最大数である最小の損失、との国を選択します。しかし、複数の最適解が存在する場合、複数のソリューションを持っている可能性が最も高い迎撃ミサイルの数は、我々はランダムに行動のための青写真として、最終的な迎撃ミサイルを選択します。

私たちはスパイでは各ミサイルが遮断された、あなたのタスクは、上記の決定の実施に確率を計算することで、すべての敵のミサイルの高さとスピードを得ています。

入力:

最初の行は、正の整数含ま\を(N- \) 敵のミサイルの数を表します。

ここでは\(N \)ラインのすべての敵のミサイルに情報を与えるために:

最初の\(I + 1 \)ラインが含まれて\(2 \)正の整数\(H_I \)\(V_I \)は、最初の表現\(Iは\)高度とミサイルの速度を。

出力:

2本の出力線を備えます。

最初のラインアウトインターセプトするミサイルの最大数を表す正の整数。

2行目は含まれてい\(N- \) A \(0 \)する\(1 \)の間の実数、\は(私は\)数はIIミサイルを傍受される確率を示し(あなたはできるだけ多く維持することができます有効桁数)。

アイデア:

最初の質問ならば考えてもよいについて\(DP [j]が\)することができます\(DP [I] \)のアップデート、条件が満たされなければならない:
1、\(私は<J \)を
2、\(H_I> = h_j \)
。3、\(V_I> = v_J \)
CDQにおける三次元の部分的順序付けの問題が直接CDQを維持することができる、すなわち3つの制約は、であり、\(ID \)によれば、2つのセクションに分割され\( V \)ソートする、その後、フェンウィックツリーメンテナンス\(時間\)

その後、我々は2番目の質問を検討することができます。
各ミサイルは、プログラムが迎撃ミサイルを指し番組の確率=ミサイルプログラムの数が表示されます/合計数は、プログラムのほとんどに到達することができます傍受されました。
ここで二つの配列を記録し、\([I] SUM \)を示す\(DP [I] \)幾つ転送方法、([I] \がSZ)\で表される\(Iは\)逆転送を多くの種類の最大転送を実現するには、いくつかのプログラムがあります。
場合\(n-は\)比較的小さく、それは直接考慮することができる\(N ^ 2 \)が算出されます。

 for(int i=n; i>=1; i--) {
            if(dp[i]==ans)cnt[i]=1;
            if(dp[i]==1)sum[i]=1;
        }
        for(int j=1; j<=n; j++)
            for(int i=j+1; i<=n; i++) {
                if(dp[i]==dp[j]+1&&a[j].h>=a[i].h&&a[j].v>=a[i].v)sum[i]+=sum[j];
            }
        for(int i=1; i<=n; i++)if(dp[i]==ans)tot+=sum[i];//用来计算总的方案数
        for(int i=n; i>=1; i--)
            for(int j=i-1; j>=1; j--)
                if(dp[i]==dp[j]+1&&a[j].h>=a[i].h&&a[j].v>=a[i].v)cnt[j]+=cnt[i];

しかし、\(N \)それは大丈夫ではないとき、明らかにあなたはCDQを進めることができますので、この時間は、我々は、3つの制限がまだ存在して見ることができる比較的大きいです。
ため\(SUM [i]は\)を直接(それらが正シーケンスであるため)、ツリーにのみ、複数の数値列を覚えている最初のCDQで処理することができるしばらく\(SZ \) CDQ各第一の処理その後、右の範囲となります。条件がある場合に戻る更新\(DP [J] == DP [i]を+1 \) 最大に、この配列ポイントに木の最大値を指定できますが、いくつかの数値を取る記録は、各更新時間だけ、次いで約を宣告\(DP [i]が+ MX \) の最大値に等しいです。

注意:あなたは二重の長い長いを結びつけることができるようにプログラムの総数はオープンになります

#include<bits/stdc++.h>
#define M 50005
#define db double
#define lowbit(x) (x&-x)
using namespace std;
bool cur1;
int n,b[M],c[M],id1,id2,dp[M],ans,Dp[M];
db sum[M],sz[M];
struct node {
    int h,v,id;
    bool operator<(const node&_)const {
        if(v!=_.v)return v>_.v;
        return h>_.h;
    }
} a[M],Q[M],C[M];
struct Tree {
    int cnt[M];
    db Sum[M];
    void Init() {
        for(int i=1; i<=id1; i++)Sum[i]=cnt[i]=0;
    }
    void add(int x,int y,db v) {
        while(x) {
            if(cnt[x]<y)cnt[x]=y,Sum[x]=v;
            else if(cnt[x]==y)Sum[x]+=v;
            x-=lowbit(x);
        }
    }
    void sum(int x,int &res,db &y) {
        res=y=0;
        while(x<=id1) {
            if(res<cnt[x])res=cnt[x],y=Sum[x];
            else if(res==cnt[x])y+=Sum[x];
            x+=lowbit(x);
        }
    }
    void clear(int x) {
        while(x)cnt[x]=0,Sum[x]=0,x-=lowbit(x);
    }
    void INit() {
        for(int i=1; i<=id1; i++)Sum[i]=cnt[i]=0;
    }
    void Add(int x,int y,db v) {
        if(x==0||y==0)return;
        while(x<=id1) {
            if(cnt[x]<y)cnt[x]=y,Sum[x]=v;
            else if(cnt[x]==y)Sum[x]+=v;
            x+=lowbit(x);
        }
    }
    void get(int x,int &res,db &y) {
        res=0,y=0;
        while(x) {
            if(res<cnt[x])res=cnt[x],y=Sum[x];
            else if(res==cnt[x])y+=Sum[x];
            x-=lowbit(x);
        }
    }
    void Clear(int x) {
        while(x<=id1)cnt[x]=Sum[x]=0,x+=lowbit(x);
    }
} T;
void CDQ(int l,int r) {
    if(l>r)return;
    if(l==r) {
        dp[l]=max(dp[l],1);
        if(dp[l]==1)sum[l]=1;
        ans=max(ans,dp[l]);
        return;
    }
    int mid=(l+r)>>1;
    CDQ(l,mid);
    for(int i=l; i<=r; i++)Q[i]=a[i],Q[i].id=i;
    sort(Q+l,Q+mid+1),sort(Q+mid+1,Q+r+1);
    int x=l,y=mid+1,now=l;
    while(x<=mid&&y<=r) {
        if(Q[x].v>=Q[y].v)C[now++]=Q[x++];
        else C[now++]=Q[y++];
    }
    while(x<=mid)C[now++]=Q[x++];
    while(y<=r)C[now++]=Q[y++];
    for(int i=l; i<=r; i++) {
        if(C[i].id<=mid)T.add(C[i].h,dp[C[i].id],sum[C[i].id]);
        else {
            int res;
            db tot;
            T.sum(C[i].h,res,tot);
            res++;
            if(res>dp[C[i].id])dp[C[i].id]=res,sum[C[i].id]=tot;
            else if(res==dp[C[i].id])sum[C[i].id]+=tot;
        }
    }
    for(int i=l; i<=r; i++)if(C[i].id<=mid)T.clear(C[i].h);
    CDQ(mid+1,r);
}
void cdq(int l,int r) {
    if(l>r)return;
    if(l==r) {
        if(dp[l]==ans)sz[l]=1;
        Dp[l]=max(Dp[l],1);
        return;
    }
    int mid=(l+r)>>1;
    cdq(mid+1,r);//先处理右区间
    for(int i=l; i<=r; i++)Q[i]=a[i],Q[i].id=i;
    sort(Q+l,Q+mid+1),sort(Q+mid+1,Q+r+1);
    int x=l,y=mid+1,now=l;
    while(x<=mid&&y<=r) {
        if(Q[x].v>=Q[y].v)C[now++]=Q[x++];
        else C[now++]=Q[y++];
    }
    while(x<=mid)C[now++]=Q[x++];
    while(y<=r)C[now++]=Q[y++];
    for(int i=r; i>=l; i--) {
        if(C[i].id>mid)T.Add(C[i].h,ans-dp[C[i].id]+1,sz[C[i].id]);
        else {
            int res;
            db tot;
            T.get(C[i].h,res,tot);
            if(res+dp[C[i].id]==ans)Dp[C[i].id]=res+1,sz[C[i].id]+=tot;
        }
    }
    for(int i=l; i<=r; i++)if(C[i].id>mid)T.Clear(C[i].h);
    cdq(l,mid);
}
struct P2 {
    void solve() {
        ans=0;
        T.Init(),CDQ(1,n);
        printf("%d\n",ans);
    }
} p2;
struct P3 {
    void solve() {
        T.INit();
        db tot=0;
        cdq(1,n);
        for(int i=1; i<=n; i++)if(dp[i]==ans)tot+=sum[i];//计算总的方案
        for(int i=1; i<=n; i++) {
            printf("%.5lf",1.0*sz[i]*sum[i]/tot);
            if(i!=n)printf(" ");
            else printf("\n");
        }
    }
} p3;
bool cur2;
int main() {
//  printf("%lf\n",(&cur2-&cur1)/1024.0/1024);
//  freopen("2.in","r",stdin);
    freopen("missile.in","r",stdin);
    freopen("missile.out","w",stdout);
    scanf("%d",&n);
    for(int i=1; i<=n; i++)scanf("%d%d",&a[i].h,&a[i].v),b[++id1]=a[i].h,c[++id2]=a[i].v;
    sort(b+1,b+id1),sort(c+1,c+id2);
    id1=unique(b+1,b+id1)-b-1;
    id2=unique(c+1,c+id2)-c-1;
    for(int i=1; i<=n; i++) {
        a[i].h=lower_bound(b+1,b+id1,a[i].h)-b;
        a[i].v=lower_bound(c+1,c+id2,a[i].v)-c;
    }
    p2.solve();
    p3.solve();
    return 0;
}

おすすめ

転載: www.cnblogs.com/cly1231/p/11334050.html