Bzoj2244: [SDOI2011]拦截导弹

题面

传送门

Sol

每个导弹有时间,高度,速度
求时间递增,高度,速度不降的最长的序列
然后还要求最长序列的方案以及每个导弹在最长序列中的方案

这个就是偏序问题辣,正反两遍求出每个导弹为结尾开头的序列最长长度
判断是否在最长序列就二者相加判断
然后记录下方案,用 double d o u b l e long long l o n g   l o n g 会炸

然后我选择 CDQ C D Q

# include <bits/stdc++.h>
# define RG register
# define IL inline
# define Fill(a, b) memset(a, b, sizeof(a))
using namespace std;
const int _(5e4 + 5);
typedef long long ll;

IL int Input(){
    RG int x = 0, z = 1; RG char c = getchar();
    for(; c < '0' || c > '9'; c = getchar()) z = c == '-' ? -1 : 1;
    for(; c >= '0' && c <= '9'; c = getchar()) x = (x << 1) + (x << 3) + (c ^ 48);
    return x * z;
}

int n, g[2][_], c1[_], o1[_], len1, o2[_], len2;
double f[2][_], c2[_];
struct Missile{
    int id, h, v;

    IL void Reverse(){
        id = n - id + 1, h = len1 - h + 1, v = len2 - v + 1;
    }

    IL int operator <(RG Missile B) const{
        return h != B.h ? h < B.h : id < B.id;
    }
} q[_], p[_];

IL void Cls(RG int x){
    for(; x <= len2; x += x & -x) c1[x] = c2[x] = 0;
}

IL void Add(RG int x, RG int l, RG double p){
    for(; x <= len2; x += x & -x)
        if(l > c1[x]) c1[x] = l, c2[x] = p;
        else if(l == c1[x]) c2[x] += p;
}

IL void Query(RG int x, RG int &l, RG double &p){
    for(; x; x -= x & -x)
        if(c1[x] > l) l = c1[x], p = c2[x];
        else if(c1[x] == l) p += c2[x];
}

IL void CDQ(RG int l, RG int r, RG int op){
    if(l == r) return;
    RG int mid = (l + r) >> 1;
    for(RG int i = l, be = l, en = mid + 1; i <= r; ++i)
        if(q[i].id <= mid) p[be++] = q[i];
        else p[en++] = q[i];
    for(RG int i = l; i <= r; ++i) q[i] = p[i];
    CDQ(l, mid, op);
    for(RG int i = mid + 1, j = l; i <= r; ++i){
        while(j <= mid && q[j].h <= q[i].h) Add(q[j].v, g[op][q[j].id] + 1, f[op][q[j].id]), ++j;
        Query(q[i].v, g[op][q[i].id], f[op][q[i].id]);
    }
    for(RG int i = l; i <= mid; ++i) Cls(q[i].v);
    CDQ(mid + 1, r, op);
    for(RG int i = l, be = l, en = mid + 1; i <= r; ++i)
        if(en > r || (be <= mid && q[be].h <= q[en].h)) p[i] = q[be++];
        else p[i] = q[en++];
    for(RG int i = l; i <= r; ++i) q[i] = p[i];
}

int main(RG int argc, RG char* argv[]){
    n = Input();
    for(RG int i = 1; i <= n; ++i){
        q[i] = (Missile){i, Input(), Input()};
        o1[++len1] = q[i].h, o2[++len2] = q[i].v;
    }
    sort(o1 + 1, o1 + len1 + 1), sort(o2 + 1, o2 + len2 + 1);
    len1 = unique(o1 + 1, o1 + len1 + 1) - o1 - 1;
    len2 = unique(o2 + 1, o2 + len2 + 1) - o2 - 1;
    for(RG int i = 1; i <= n; ++i){
        q[i].h = lower_bound(o1 + 1, o1 + len1 + 1, q[i].h) - o1;
        q[i].v = lower_bound(o2 + 1, o2 + len2 + 1, q[i].v) - o2;
        q[i].h = len1 - q[i].h + 1, q[i].v = len2 - q[i].v + 1;
        g[0][i] = g[1][i] = 1, f[0][i] = f[1][i] = 1;
    }
    sort(q + 1, q + n + 1), CDQ(1, n, 0);
    for(RG int i = 1; i <= n; ++i) q[i].Reverse();
    sort(q + 1, q + n + 1), CDQ(1, n, 1);
    reverse(g[1] + 1, g[1] + n + 1), reverse(f[1] + 1, f[1] + n + 1);
    RG int mx = 0; RG double sum = 0;
    for(RG int i = 1; i <= n; ++i) mx = max(mx, g[0][i]);
    printf("%d\n", mx);
    for(RG int i = 1; i <= n; ++i) if(g[0][i] == mx) sum += f[0][i];
    for(RG int i = 1; i <= n; ++i){
        if(g[0][i] + g[1][i] - 1 != mx) puts("0");
        else printf("%.5lf\n", f[0][i] * f[1][i] / sum);
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值