ZOJ 3597 Hit the Target! (线段树扫描线 -- 矩形所能覆盖的最多的点数)
题意是说有n把枪,有m个靶子,每把枪只有一发子弹(也就是说一把枪最多只能打一个靶子), 告诉你第 i 把枪可以打到第j个靶, 现在等概率的出现一个连续的P把枪,在知道这P把枪之后,你被允许选择一个连续的Q个靶子,使得这P把枪所打到的靶子的数目最多,问打到的靶子数目的期望值是多少。
这题通过简单的转化就可以转换成为另一个模型:
如果第a把枪可以打到第b个靶子,那么将其视为二位平面上的一个点(b, a), 问题转化为一个Q * P的矩形最多可以覆盖多少个点。只是有一点需要注意的就是同一把枪只能打到一个靶子,所以在a相等的情况下最多只能覆盖一个b。
至于如何求矩形覆盖点的个数,我这也是第一次写,所以查阅了有关资料。
方法是将矩形的右界作为参考点,找出参考点在哪一个区间(线段)内矩形都可以覆盖到这个点,这样每一个点就对应y相等的一段线段,原题就转化成为了高度y小于P的区间内某一个位置x上的覆盖次数的最大值,可以用线段树的离线操作(扫描线)来完成。
1 #include <map> 2 #include <set> 3 #include <stack> 4 #include <queue> 5 #include <cmath> 6 #include <ctime> 7 #include <vector> 8 #include <cstdio> 9 #include <cctype> 10 #include <cstring> 11 #include <cstdlib> 12 #include <iostream> 13 #include <algorithm> 14 using namespace std; 15 #define INF 0x3f3f3f3f 16 #define inf (-((LL)1<<40)) 17 #define lson k<<1, L, (L + R)>>1 18 #define rson k<<1|1, ((L + R)>>1) + 1, R 19 #define mem0(a) memset(a,0,sizeof(a)) 20 #define mem1(a) memset(a,-1,sizeof(a)) 21 #define mem(a, b) memset(a, b, sizeof(a)) 22 #define FIN freopen("in.txt", "r", stdin) 23 #define FOUT freopen("out.txt", "w", stdout) 24 #define rep(i, a, b) for(int i = a; i <= b; i ++) 25 26 template<class T> T CMP_MIN(T a, T b) { return a < b; } 27 template<class T> T CMP_MAX(T a, T b) { return a > b; } 28 template<class T> T MAX(T a, T b) { return a > b ? a : b; } 29 template<class T> T MIN(T a, T b) { return a < b ? a : b; } 30 template<class T> T GCD(T a, T b) { return b ? GCD(b, a%b) : a; } 31 template<class T> T LCM(T a, T b) { return a / GCD(a,b) * b; } 32 33 //typedef __int64 LL; 34 typedef long long LL; 35 const int MAXN = 51000; 36 const int MAXM = 110000; 37 const double eps = 1e-4; 38 //LL MOD = 987654321; 39 40 #define OK(i) (i > 0 && p[i - 1].y == p[i].y && p[i].x <= p[i - 1].x + Q - 1) 41 42 int T, N, M, P, Q, K; 43 struct Point { 44 int x, y; 45 bool operator < (const Point &A) const { 46 return y == A.y ? x < A.x : y < A.y; 47 } 48 }p[MAXM]; 49 50 struct SegTree { 51 LL ma[MAXN<<2], add[MAXN<<2]; 52 53 void build(int k, int L, int R) { 54 ma[k] = add[k] = 0; 55 if(L == R) return ; 56 build(lson); build(rson); 57 } 58 59 void pushDown(int k) { 60 ma[k<<1] += add[k]; add[k<<1] += add[k]; 61 ma[k<<1|1] += add[k]; add[k<<1|1] += add[k]; 62 add[k] = 0; 63 } 64 65 void update(int k, int L, int R, int l, int r, int val) { 66 if(R < l || L > r) return ; 67 if(l <= L && R <= r) { ma[k] += val; add[k] += val; return ; } 68 pushDown(k); 69 update(lson, l, r, val); 70 update(rson, l, r, val); 71 ma[k] = max(ma[k<<1], ma[k<<1|1]); 72 } 73 74 LL query(int k, int L, int R, int l, int r) { 75 if(R < l || L > r) return 0; 76 if(l <= L && R <= r) return ma[k]; 77 pushDown(k); 78 return max(query(lson, l, r), query(rson, l, r)); 79 } 80 81 }segTree; 82 83 int main() 84 { 85 //FIN; 86 while(~scanf("%d", &T)) while(T--) 87 { 88 scanf("%d %d %d %d %d", &N, &M, &P, &Q, &K); 89 rep (i, 0, K - 1) scanf("%d %d", &p[i].y, &p[i].x); 90 sort(p, p + K); 91 92 segTree.build(1, 1, M); 93 LL ans = 0, fr = 0, re = 0; 94 rep (i, P, N) { 95 while(fr < K && p[fr].y <= i) { 96 int st = OK(fr) ? p[fr-1].x + Q : p[fr].x; 97 int ed = min(p[fr].x + Q - 1, M); 98 segTree.update(1, 1, M, st, ed, 1); 99 fr ++; 100 } 101 while(i - p[re].y >= P) { 102 int st = OK(re) ? p[re-1].x + Q : p[re].x; 103 int ed = min(p[re].x + Q - 1, M); 104 segTree.update(1, 1, M, st, ed, -1); 105 re ++; 106 } 107 ans += segTree.query(1, 1, M, 1, M); 108 } 109 printf("%.2lf\n", (double)ans / (N - P + 1)); 110 } 111 return 0; 112 }