题意是说有n把枪,有m个靶子,每把枪只有一发子弹(也就是说一把枪最多只能打一个靶子), 告诉你第 i 把枪可以打到第j个靶, 现在等概率的出现一个连续的P把枪,在知道这P把枪之后,你被允许选择一个连续的Q个靶子,使得这P把枪所打到的靶子的数目最多,问打到的靶子数目的期望值是多少。
这题通过简单的转化就可以转换成为另一个模型:
如果第a把枪可以打到第b个靶子,那么将其视为二位平面上的一个点(b, a), 问题转化为一个Q * P的矩形最多可以覆盖多少个点。只是有一点需要注意的就是同一把枪只能打到一个靶子,所以在a相等的情况下最多只能覆盖一个b。
至于如何求矩形覆盖点的个数,我这也是第一次写,所以查阅了有关资料。
方法是将矩形的右界作为参考点,找出参考点在哪一个区间(线段)内矩形都可以覆盖到这个点,这样每一个点就对应y相等的一段线段,原题就转化成为了高度y小于P的区间内某一个位置x上的覆盖次数的最大值,可以用线段树的离线操作(扫描线)来完成。
#include <map>
#include <set>
#include <stack>
#include <queue>
#include <cmath>
#include <ctime>
#include <vector>
#include <cstdio>
#include <cctype>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
using namespace std;
#define INF 0x3f3f3f3f
#define inf (-((LL)1<<40))
#define lson k<<1, L, (L + R)>>1
#define rson k<<1|1, ((L + R)>>1) + 1, R
#define mem0(a) memset(a,0,sizeof(a))
#define mem1(a) memset(a,-1,sizeof(a))
#define mem(a, b) memset(a, b, sizeof(a))
#define FIN freopen("in.txt", "r", stdin)
#define FOUT freopen("out.txt", "w", stdout)
#define rep(i, a, b) for(int i = a; i <= b; i ++) template<class T> T CMP_MIN(T a, T b) { return a < b; }
template<class T> T CMP_MAX(T a, T b) { return a > b; }
template<class T> T MAX(T a, T b) { return a > b ? a : b; }
template<class T> T MIN(T a, T b) { return a < b ? a : b; }
template<class T> T GCD(T a, T b) { return b ? GCD(b, a%b) : a; }
template<class T> T LCM(T a, T b) { return a / GCD(a,b) * b; } //typedef __int64 LL;
typedef long long LL;
const int MAXN = ;
const int MAXM = ;
const double eps = 1e-;
//LL MOD = 987654321; #define OK(i) (i > 0 && p[i - 1].y == p[i].y && p[i].x <= p[i - 1].x + Q - 1) int T, N, M, P, Q, K;
struct Point {
int x, y;
bool operator < (const Point &A) const {
return y == A.y ? x < A.x : y < A.y;
}
}p[MAXM]; struct SegTree {
LL ma[MAXN<<], add[MAXN<<]; void build(int k, int L, int R) {
ma[k] = add[k] = ;
if(L == R) return ;
build(lson); build(rson);
} void pushDown(int k) {
ma[k<<] += add[k]; add[k<<] += add[k];
ma[k<<|] += add[k]; add[k<<|] += add[k];
add[k] = ;
} void update(int k, int L, int R, int l, int r, int val) {
if(R < l || L > r) return ;
if(l <= L && R <= r) { ma[k] += val; add[k] += val; return ; }
pushDown(k);
update(lson, l, r, val);
update(rson, l, r, val);
ma[k] = max(ma[k<<], ma[k<<|]);
} LL query(int k, int L, int R, int l, int r) {
if(R < l || L > r) return ;
if(l <= L && R <= r) return ma[k];
pushDown(k);
return max(query(lson, l, r), query(rson, l, r));
} }segTree; int main()
{
//FIN;
while(~scanf("%d", &T)) while(T--)
{
scanf("%d %d %d %d %d", &N, &M, &P, &Q, &K);
rep (i, , K - ) scanf("%d %d", &p[i].y, &p[i].x);
sort(p, p + K); segTree.build(, , M);
LL ans = , fr = , re = ;
rep (i, P, N) {
while(fr < K && p[fr].y <= i) {
int st = OK(fr) ? p[fr-].x + Q : p[fr].x;
int ed = min(p[fr].x + Q - , M);
segTree.update(, , M, st, ed, );
fr ++;
}
while(i - p[re].y >= P) {
int st = OK(re) ? p[re-].x + Q : p[re].x;
int ed = min(p[re].x + Q - , M);
segTree.update(, , M, st, ed, -);
re ++;
}
ans += segTree.query(, , M, , M);
}
printf("%.2lf\n", (double)ans / (N - P + ));
}
return ;
}