给一个 (n imes m) 的网格,让你在里面放刚好 (k) 条鱼(位置不能相同),随机用一个 (r imes r) 的网覆盖(共 ((n - r + 1)(m - r + 1)) 种方法),最大化覆盖到鱼的数量的期望。
由期望的线性性,答案是每个格子被访问到的期望。我们不妨先将答案乘上 ((n - r + 1)(m - r + 1)) 来考虑。
我们想象有一个滑动的窗口,它只在 (x) 轴滑和只在 (y) 轴滑的过程——实际上两维是独立的。
对于一维,记长度为 (n),考虑左端点可行位置,得到一个数组 (A_i = min(i, n - r + 1) - max(1, i - r + 1) + 1)
那么,在每个位置的贡献就是 (x) 轴数组 (A) 和 (y) 轴数组 (B) 的笛卡尔积 (M_{i,j} = A_i B_j)。
(A) 和 (B) 显然是单峰的(当然也是对称的),所以笛卡尔积之后也是单峰的。
daklqw@daklqw:~/workspace/code$ ./fish
12 17 9
1 2 3 4 5 6 7 8 9 8 7 6 5 4 3 2 1
2 4 6 8 10 12 14 16 18 16 14 12 10 8 6 4 2
3 6 9 12 15 18 21 24 27 24 21 18 15 12 9 6 3
4 8 12 16 20 24 28 32 36 32 28 24 20 16 12 8 4
4 8 12 16 20 24 28 32 36 32 28 24 20 16 12 8 4
4 8 12 16 20 24 28 32 36 32 28 24 20 16 12 8 4
4 8 12 16 20 24 28 32 36 32 28 24 20 16 12 8 4
4 8 12 16 20 24 28 32 36 32 28 24 20 16 12 8 4
4 8 12 16 20 24 28 32 36 32 28 24 20 16 12 8 4
3 6 9 12 15 18 21 24 27 24 21 18 15 12 9 6 3
2 4 6 8 10 12 14 16 18 16 14 12 10 8 6 4 2
1 2 3 4 5 6 7 8 9 8 7 6 5 4 3 2 1
daklqw@daklqw:~/workspace/code$ ./fish
3 3 2
1 2 1
2 4 2
1 2 1
所以我们直接从最中间开始贪心,用 BFS 和 优先队列找到前 k 大的位置即可。
下面是远古时期的代码:
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <queue>
#include <set>
using namespace std;
int n,m,r,k;
const int ways[4][2]={{1,0},{0,1},{-1,0},{0,-1}};
double ans,tot;
struct element{
int x,y;long long val;
inline bool operator<(const element & b)const{
return val<b.val;
}
};
inline long long getv(int x,int y){
int t1=max(x-r+1,1),t2=max(y-r+1,1),
t3=min(x+r-1,n)-r+1,t4=min(y+r-1,m)-r+1;
if(t3<t1|t4<t2)return -1;
return 1LL*(t3-t1+1)*(t4-t2+1);
}
priority_queue<element>q;
set<pair<int,int> >s;
int main(){
scanf("%d%d%d%d",&n,&m,&r,&k);
if(n>m)swap(n,m);
q.push((element){n+1>>1,m+1>>1,getv(n+1>>1,m+1>>1)});
s.insert(make_pair(n+1>>1,m+1>>1));
for(int i=1;i<=k;++i){
element t=q.top();q.pop();
tot+=t.val;
for(register int j=0;j<4;++j){
int tx=t.x+ways[j][0],
ty=t.y+ways[j][1];
if(tx<1||ty<1||tx>n||ty>m)continue;
if(s.find(make_pair(tx,ty))!=s.end())continue;
q.push((element){tx,ty,getv(tx,ty)});
s.insert(make_pair(tx,ty));
}
}
printf("%.10lf
",tot/double(n-r+1)/double(m-r+1));
return 0;
}