题解
⭐:在有规律的矩阵中求最大值,可以考虑使用类最短路的搜索。
易得答案为(k)个格子覆盖次数和(div (n-r+1)^2),因此只需找出覆盖次数最大的(k)个格子。所以——打表找规律!
格子((tx,ty))被覆盖的次数如下:设(x=min(tx,n-tx+1),y=min(ty,m-ty+1))(上下、左右对称),次数(=min(r,n-r+1,x)cdot min(r,m-r+1,y))。其实也可以推导得出:若矩形无限大,覆盖次数一定(=r^2)(网中所有位置均占一遍);但矩形的边界限制其上下最多(x)个,左右最多(y)个;至于(n-r+1,m-r+1)则是行列最多覆盖次数,3者取(min),乘积即为答案。
由上式得覆盖次数中间最大,四周最小。因此我们可以由((lceil frac{n}{2} ceil,lceil frac{m}{2} ceil))开始进行BFS,每次向上下左右扩展,并将扩展格子放入优先队列(大根堆)中。进行(k)次求和即可。
AC代码
#include<bits/stdc++.h>
#define int long long
#define mp make_pair
using namespace std;
struct node
{
int x,y,v;
bool operator < (const node& a) const {return v<a.v;}
};
int n,m,r;
priority_queue<node> q;
map<pair<int,int>,bool> vis;
int cul(int x,int y)//求(x,y)的覆盖次数
{
if(x>(n+1)/2) x=n-x+1;
if(y>(m+1)/2) y=m-y+1;
x=min(min(r,n-r+1),x),y=min(min(r,m-r+1),y);
return x*y;
}
bool ok(int x,int y) {return 1<=x && x<=n && 1<=y && y<=m && !vis[mp(x,y)];}
signed main()
{
int k,sum=0,cnt=0;
scanf("%lld%lld%lld%lld",&n,&m,&r,&k);
q.push((node){(n+1)/2,(m+1)/2,cul((n+1)/2,(m+1)/2)}),vis[mp((n+1)/2,(m+1)/2)]=1;
while(!q.empty())
{
cnt++; sum+=q.top().v;
if(cnt==k) break;
int x=q.top().x,y=q.top().y; q.pop();
if(ok(x+1,y)) q.push((node){x+1,y,cul(x+1,y)}),vis[mp(x+1,y)]=1;
if(ok(x,y+1)) q.push((node){x,y+1,cul(x,y+1)}),vis[mp(x,y+1)]=1;
if(ok(x-1,y)) q.push((node){x-1,y,cul(x-1,y)}),vis[mp(x-1,y)]=1;
if(ok(x,y-1)) q.push((node){x,y-1,cul(x,y-1)}),vis[mp(x,y-1)]=1;
}
double ans=sum*1.0/((n-r+1)*(m-r+1));
printf("%0.10f",ans);
return 0;
}