Bzoj2244: [SDOI2011]拦截导弹

题面

传送门

Sol

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

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

然后我选择\(CDQ\)

# 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;
}
posted @ 2018-04-04 15:31  Cyhlnj  阅读(136)  评论(0编辑  收藏  举报